* [PATCH] libsanitizer: merge from master
@ 2021-05-13 7:28 Martin Liška
2021-05-13 15:54 ` H.J. Lu
2021-06-04 7:32 ` [PATCH] libsanitizer: merge from master Hongtao Liu
0 siblings, 2 replies; 17+ messages in thread
From: Martin Liška @ 2021-05-13 7:28 UTC (permalink / raw)
To: GCC Patches
I'm planning to do merge from master twice a year.
This merge was tested on x86_64-linux-gnu and ppc64le-linux-gnu
and survives regression tests.
Pushed to master.
Thanks,
Martin
Merged revision: f58e0513dd95944b81ce7a6e7b49ba656de7d75f
---
libsanitizer/MERGE | 2 +-
libsanitizer/asan/asan_allocator.cpp | 32 +-
libsanitizer/asan/asan_descriptions.cpp | 19 +-
libsanitizer/asan/asan_descriptions.h | 13 +-
libsanitizer/asan/asan_errors.cpp | 7 +-
libsanitizer/asan/asan_fake_stack.cpp | 2 +-
libsanitizer/asan/asan_fuchsia.cpp | 2 +-
libsanitizer/asan/asan_globals.cpp | 19 +
libsanitizer/asan/asan_interceptors.cpp | 41 +-
libsanitizer/asan/asan_interceptors.h | 21 +-
libsanitizer/asan/asan_linux.cpp | 3 +-
libsanitizer/asan/asan_mapping.h | 25 +-
libsanitizer/asan/asan_new_delete.cpp | 2 +-
libsanitizer/asan/asan_poisoning.cpp | 2 +-
libsanitizer/asan/asan_posix.cpp | 2 +-
libsanitizer/asan/asan_rtl.cpp | 20 +-
libsanitizer/asan/asan_stack.h | 9 -
libsanitizer/asan/asan_thread.cpp | 51 +-
libsanitizer/asan/asan_thread.h | 6 +-
libsanitizer/asan/asan_win.cpp | 2 +-
libsanitizer/builtins/assembly.h | 98 +++-
libsanitizer/hwasan/hwasan.cpp | 19 +-
libsanitizer/hwasan/hwasan.h | 41 +-
libsanitizer/hwasan/hwasan_allocator.cpp | 28 +-
libsanitizer/hwasan/hwasan_allocator.h | 19 +-
libsanitizer/hwasan/hwasan_checks.h | 5 +-
libsanitizer/hwasan/hwasan_dynamic_shadow.cpp | 16 +-
libsanitizer/hwasan/hwasan_flags.h | 2 +
libsanitizer/hwasan/hwasan_flags.inc | 9 +
libsanitizer/hwasan/hwasan_interceptors.cpp | 3 +-
.../hwasan/hwasan_interceptors_vfork.S | 3 +
.../hwasan/hwasan_interface_internal.h | 3 +
libsanitizer/hwasan/hwasan_linux.cpp | 41 +-
libsanitizer/hwasan/hwasan_mapping.h | 2 +
libsanitizer/hwasan/hwasan_memintrinsics.cpp | 4 +-
libsanitizer/hwasan/hwasan_new_delete.cpp | 39 ++
libsanitizer/hwasan/hwasan_report.cpp | 26 +-
libsanitizer/hwasan/hwasan_setjmp.S | 6 +
.../hwasan/hwasan_tag_mismatch_aarch64.S | 6 +
libsanitizer/hwasan/hwasan_thread.cpp | 15 +-
libsanitizer/hwasan/hwasan_thread.h | 4 +-
libsanitizer/hwasan/hwasan_thread_list.h | 90 ++--
.../include/sanitizer/common_interface_defs.h | 3 +
.../include/sanitizer/dfsan_interface.h | 16 +
.../include/sanitizer/hwasan_interface.h | 3 +
.../include/sanitizer/memprof_interface.h | 5 +
.../include/sanitizer/tsan_interface.h | 17 +-
.../include/sanitizer/tsan_interface_atomic.h | 2 +-
.../interception/interception_linux.cpp | 6 +-
.../interception/interception_linux.h | 6 +-
.../interception/interception_win.cpp | 6 +-
libsanitizer/lsan/lsan_allocator.cpp | 26 +-
libsanitizer/lsan/lsan_allocator.h | 2 +-
libsanitizer/lsan/lsan_common.cpp | 234 ++++++---
libsanitizer/lsan/lsan_common.h | 9 +-
libsanitizer/lsan/lsan_common_fuchsia.cpp | 4 +-
libsanitizer/lsan/lsan_fuchsia.h | 2 +-
libsanitizer/lsan/lsan_interceptors.cpp | 2 +-
libsanitizer/lsan/lsan_posix.cpp | 6 +-
libsanitizer/lsan/lsan_thread.cpp | 2 +-
.../sanitizer_allocator_combined.h | 4 +-
.../sanitizer_allocator_primary32.h | 3 +-
.../sanitizer_allocator_primary64.h | 93 +++-
.../sanitizer_allocator_size_class_map.h | 2 +-
.../sanitizer_atomic_clang_mips.h | 8 +-
.../sanitizer_chained_origin_depot.cpp | 108 +++++
.../sanitizer_chained_origin_depot.h | 88 ++++
.../sanitizer_common/sanitizer_common.cpp | 10 +-
.../sanitizer_common/sanitizer_common.h | 82 +++-
.../sanitizer_common_interceptors.inc | 19 +-
.../sanitizer_common_interceptors_ioctl.inc | 6 +-
...er_common_interceptors_vfork_aarch64.inc.S | 5 +
.../sanitizer_common_interface.inc | 1 +
.../sanitizer_common_libcdep.cpp | 7 +-
.../sanitizer_common/sanitizer_file.cpp | 13 +
.../sanitizer_common/sanitizer_file.h | 1 +
.../sanitizer_common/sanitizer_flags.cpp | 7 +
.../sanitizer_common/sanitizer_flags.inc | 2 +
.../sanitizer_common/sanitizer_fuchsia.cpp | 72 +--
.../sanitizer_interface_internal.h | 4 +
.../sanitizer_internal_defs.h | 3 +
.../sanitizer_common/sanitizer_libignore.cpp | 2 +-
.../sanitizer_common/sanitizer_linux.cpp | 72 +--
.../sanitizer_common/sanitizer_linux.h | 3 +-
.../sanitizer_linux_libcdep.cpp | 447 ++++++++++--------
.../sanitizer_local_address_space_view.h | 2 +-
.../sanitizer_common/sanitizer_mac.cpp | 141 +++++-
libsanitizer/sanitizer_common/sanitizer_mac.h | 37 --
.../sanitizer_common/sanitizer_malloc_mac.inc | 6 +-
.../sanitizer_common/sanitizer_netbsd.cpp | 6 +
.../sanitizer_common/sanitizer_platform.h | 27 +-
.../sanitizer_platform_interceptors.h | 113 +++--
.../sanitizer_platform_limits_freebsd.cpp | 3 +
.../sanitizer_platform_limits_linux.cpp | 7 +-
.../sanitizer_platform_limits_posix.cpp | 85 ++--
.../sanitizer_platform_limits_posix.h | 4 +-
.../sanitizer_common/sanitizer_posix.cpp | 4 +-
.../sanitizer_common/sanitizer_posix.h | 4 +
.../sanitizer_posix_libcdep.cpp | 2 +-
.../sanitizer_common/sanitizer_printf.cpp | 57 ++-
.../sanitizer_procmaps_common.cpp | 2 +-
.../sanitizer_procmaps_mac.cpp | 4 +-
.../sanitizer_procmaps_solaris.cpp | 4 +-
.../sanitizer_common/sanitizer_ptrauth.h | 20 +-
.../sanitizer_common/sanitizer_stackdepot.cpp | 3 +-
.../sanitizer_common/sanitizer_stacktrace.cpp | 20 +-
.../sanitizer_common/sanitizer_stacktrace.h | 2 -
.../sanitizer_stacktrace_libcdep.cpp | 8 +-
.../sanitizer_stoptheworld_linux_libcdep.cpp | 5 +
.../sanitizer_suppressions.cpp | 4 +-
.../sanitizer_symbolizer_libcdep.cpp | 2 +-
.../sanitizer_symbolizer_markup.cpp | 4 +
.../sanitizer_symbolizer_posix_libcdep.cpp | 11 +-
.../sanitizer_symbolizer_report.cpp | 6 +-
.../sanitizer_symbolizer_win.cpp | 18 +-
.../sanitizer_termination.cpp | 33 +-
.../sanitizer_thread_registry.cpp | 14 +-
.../sanitizer_thread_registry.h | 7 +-
.../sanitizer_tls_get_addr.cpp | 79 ++--
.../sanitizer_common/sanitizer_tls_get_addr.h | 21 +-
.../sanitizer_common/sanitizer_unwind_win.cpp | 7 +
.../sanitizer_common/sanitizer_win.cpp | 84 ++--
libsanitizer/tsan/tsan_clock.cpp | 37 +-
libsanitizer/tsan/tsan_clock.h | 16 +-
libsanitizer/tsan/tsan_defs.h | 2 -
libsanitizer/tsan/tsan_dense_alloc.h | 32 +-
libsanitizer/tsan/tsan_external.cpp | 4 +-
libsanitizer/tsan/tsan_interceptors_mac.cpp | 1 +
libsanitizer/tsan/tsan_interceptors_posix.cpp | 149 ++++--
libsanitizer/tsan/tsan_interface.cpp | 8 +-
libsanitizer/tsan/tsan_interface.h | 9 +-
libsanitizer/tsan/tsan_interface_inl.h | 22 +-
libsanitizer/tsan/tsan_mman.cpp | 2 +-
libsanitizer/tsan/tsan_platform.h | 121 ++++-
libsanitizer/tsan/tsan_platform_linux.cpp | 23 +-
libsanitizer/tsan/tsan_platform_mac.cpp | 9 +-
libsanitizer/tsan/tsan_platform_posix.cpp | 2 +-
libsanitizer/tsan/tsan_report.cpp | 14 +-
libsanitizer/tsan/tsan_rtl.cpp | 129 +++--
libsanitizer/tsan/tsan_rtl.h | 11 +-
libsanitizer/tsan/tsan_rtl_mutex.cpp | 25 +-
libsanitizer/tsan/tsan_rtl_ppc64.S | 1 -
libsanitizer/tsan/tsan_rtl_report.cpp | 56 ++-
libsanitizer/tsan/tsan_rtl_thread.cpp | 13 +-
libsanitizer/tsan/tsan_sync.cpp | 4 +-
libsanitizer/tsan/tsan_sync.h | 8 +-
libsanitizer/ubsan/ubsan_diag.cpp | 8 +-
libsanitizer/ubsan/ubsan_flags.cpp | 1 -
libsanitizer/ubsan/ubsan_handlers.cpp | 15 -
libsanitizer/ubsan/ubsan_handlers.h | 8 -
libsanitizer/ubsan/ubsan_init.cpp | 9 +
libsanitizer/ubsan/ubsan_monitor.cpp | 6 +-
libsanitizer/ubsan/ubsan_platform.h | 4 +-
153 files changed, 2538 insertions(+), 1239 deletions(-)
create mode 100644 libsanitizer/sanitizer_common/sanitizer_chained_origin_depot.cpp
create mode 100644 libsanitizer/sanitizer_common/sanitizer_chained_origin_depot.h
diff --git a/libsanitizer/MERGE b/libsanitizer/MERGE
index 0fb64a9567c..c4731d0866c 100644
--- a/libsanitizer/MERGE
+++ b/libsanitizer/MERGE
@@ -1,4 +1,4 @@
-6e7dd1e3e1170080b76b5dcc5716bdd974343233
+f58e0513dd95944b81ce7a6e7b49ba656de7d75f
The first line of this file holds the git revision number of the
last merge done from the master library sources.
diff --git a/libsanitizer/asan/asan_allocator.cpp b/libsanitizer/asan/asan_allocator.cpp
index 58b496a3ca4..7c8bb504332 100644
--- a/libsanitizer/asan/asan_allocator.cpp
+++ b/libsanitizer/asan/asan_allocator.cpp
@@ -476,7 +476,7 @@ struct Allocator {
return false;
if (m->Beg() != addr) return false;
AsanThread *t = GetCurrentThread();
- m->SetAllocContext(t ? t->tid() : 0, StackDepotPut(*stack));
+ m->SetAllocContext(t ? t->tid() : kMainTid, StackDepotPut(*stack));
return true;
}
@@ -570,7 +570,7 @@ struct Allocator {
m->SetUsedSize(size);
m->user_requested_alignment_log = user_requested_alignment_log;
- m->SetAllocContext(t ? t->tid() : 0, StackDepotPut(*stack));
+ m->SetAllocContext(t ? t->tid() : kMainTid, StackDepotPut(*stack));
uptr size_rounded_down_to_granularity =
RoundDownTo(size, SHADOW_GRANULARITY);
@@ -1183,6 +1183,34 @@ IgnoreObjectResult IgnoreObjectLocked(const void *p) {
m->lsan_tag = __lsan::kIgnored;
return kIgnoreObjectSuccess;
}
+
+void GetAdditionalThreadContextPtrs(ThreadContextBase *tctx, void *ptrs) {
+ // Look for the arg pointer of threads that have been created or are running.
+ // This is necessary to prevent false positive leaks due to the AsanThread
+ // holding the only live reference to a heap object. This can happen because
+ // the `pthread_create()` interceptor doesn't wait for the child thread to
+ // start before returning and thus loosing the the only live reference to the
+ // heap object on the stack.
+
+ __asan::AsanThreadContext *atctx =
+ reinterpret_cast<__asan::AsanThreadContext *>(tctx);
+ __asan::AsanThread *asan_thread = atctx->thread;
+
+ // Note ThreadStatusRunning is required because there is a small window where
+ // the thread status switches to `ThreadStatusRunning` but the `arg` pointer
+ // still isn't on the stack yet.
+ if (atctx->status != ThreadStatusCreated &&
+ atctx->status != ThreadStatusRunning)
+ return;
+
+ uptr thread_arg = reinterpret_cast<uptr>(asan_thread->get_arg());
+ if (!thread_arg)
+ return;
+
+ auto ptrsVec = reinterpret_cast<InternalMmapVector<uptr> *>(ptrs);
+ ptrsVec->push_back(thread_arg);
+}
+
} // namespace __lsan
// ---------------------- Interface ---------------- {{{1
diff --git a/libsanitizer/asan/asan_descriptions.cpp b/libsanitizer/asan/asan_descriptions.cpp
index 153c874a4e7..2ba8a02f841 100644
--- a/libsanitizer/asan/asan_descriptions.cpp
+++ b/libsanitizer/asan/asan_descriptions.cpp
@@ -44,11 +44,11 @@ void DescribeThread(AsanThreadContext *context) {
CHECK(context);
asanThreadRegistry().CheckLocked();
// No need to announce the main thread.
- if (context->tid == 0 || context->announced) {
+ if (context->tid == kMainTid || context->announced) {
return;
}
context->announced = true;
- InternalScopedString str(1024);
+ InternalScopedString str;
str.append("Thread %s", AsanThreadIdAndName(context).c_str());
if (context->parent_tid == kInvalidTid) {
str.append(" created by unknown thread\n");
@@ -77,7 +77,6 @@ static bool GetShadowKind(uptr addr, ShadowKind *shadow_kind) {
} else if (AddrIsInLowShadow(addr)) {
*shadow_kind = kShadowKindLow;
} else {
- CHECK(0 && "Address is not in memory and not in shadow?");
return false;
}
return true;
@@ -126,7 +125,7 @@ static void GetAccessToHeapChunkInformation(ChunkAccess *descr,
static void PrintHeapChunkAccess(uptr addr, const ChunkAccess &descr) {
Decorator d;
- InternalScopedString str(4096);
+ InternalScopedString str;
str.append("%s", d.Location());
switch (descr.access_type) {
case kAccessTypeLeft:
@@ -243,7 +242,7 @@ static void PrintAccessAndVarIntersection(const StackVarDescr &var, uptr addr,
else if (addr >= prev_var_end && addr - prev_var_end >= var.beg - addr_end)
pos_descr = "underflows";
}
- InternalScopedString str(1024);
+ InternalScopedString str;
str.append(" [%zd, %zd)", var.beg, var_end);
// Render variable name.
str.append(" '");
@@ -276,7 +275,7 @@ bool DescribeAddressIfStack(uptr addr, uptr access_size) {
// Global descriptions
static void DescribeAddressRelativeToGlobal(uptr addr, uptr access_size,
const __asan_global &g) {
- InternalScopedString str(4096);
+ InternalScopedString str;
Decorator d;
str.append("%s", d.Location());
if (addr < g.beg) {
@@ -464,7 +463,13 @@ AddressDescription::AddressDescription(uptr addr, uptr access_size,
return;
}
data.kind = kAddressKindWild;
- addr = 0;
+ data.wild.addr = addr;
+ data.wild.access_size = access_size;
+}
+
+void WildAddressDescription::Print() const {
+ Printf("Address %p is a wild pointer inside of access range of size %p.\n",
+ addr, access_size);
}
void PrintAddressDescription(uptr addr, uptr access_size,
diff --git a/libsanitizer/asan/asan_descriptions.h b/libsanitizer/asan/asan_descriptions.h
index ee0e2061559..650e2eb9173 100644
--- a/libsanitizer/asan/asan_descriptions.h
+++ b/libsanitizer/asan/asan_descriptions.h
@@ -146,6 +146,13 @@ struct StackAddressDescription {
bool GetStackAddressInformation(uptr addr, uptr access_size,
StackAddressDescription *descr);
+struct WildAddressDescription {
+ uptr addr;
+ uptr access_size;
+
+ void Print() const;
+};
+
struct GlobalAddressDescription {
uptr addr;
// Assume address is close to at most four globals.
@@ -193,7 +200,7 @@ class AddressDescription {
HeapAddressDescription heap;
StackAddressDescription stack;
GlobalAddressDescription global;
- uptr addr;
+ WildAddressDescription wild;
};
};
@@ -211,7 +218,7 @@ class AddressDescription {
uptr Address() const {
switch (data.kind) {
case kAddressKindWild:
- return data.addr;
+ return data.wild.addr;
case kAddressKindShadow:
return data.shadow.addr;
case kAddressKindHeap:
@@ -226,7 +233,7 @@ class AddressDescription {
void Print(const char *bug_descr = nullptr) const {
switch (data.kind) {
case kAddressKindWild:
- Printf("Address %p is a wild pointer.\n", data.addr);
+ data.wild.Print();
return;
case kAddressKindShadow:
return data.shadow.Print();
diff --git a/libsanitizer/asan/asan_errors.cpp b/libsanitizer/asan/asan_errors.cpp
index 541c6e0353b..e68e6971f96 100644
--- a/libsanitizer/asan/asan_errors.cpp
+++ b/libsanitizer/asan/asan_errors.cpp
@@ -343,7 +343,8 @@ void ErrorODRViolation::Print() {
Report("ERROR: AddressSanitizer: %s (%p):\n", scariness.GetDescription(),
global1.beg);
Printf("%s", d.Default());
- InternalScopedString g1_loc(256), g2_loc(256);
+ InternalScopedString g1_loc;
+ InternalScopedString g2_loc;
PrintGlobalLocation(&g1_loc, global1);
PrintGlobalLocation(&g2_loc, global2);
Printf(" [1] size=%zd '%s' %s\n", global1.size,
@@ -360,7 +361,7 @@ void ErrorODRViolation::Print() {
Report(
"HINT: if you don't care about these errors you may set "
"ASAN_OPTIONS=detect_odr_violation=0\n");
- InternalScopedString error_msg(256);
+ InternalScopedString error_msg;
error_msg.append("%s: global '%s' at %s", scariness.GetDescription(),
MaybeDemangleGlobalName(global1.name), g1_loc.data());
ReportErrorSummary(error_msg.data());
@@ -554,7 +555,7 @@ static void PrintShadowMemoryForAddress(uptr addr) {
uptr shadow_addr = MemToShadow(addr);
const uptr n_bytes_per_row = 16;
uptr aligned_shadow = shadow_addr & ~(n_bytes_per_row - 1);
- InternalScopedString str(4096 * 8);
+ InternalScopedString str;
str.append("Shadow bytes around the buggy address:\n");
for (int i = -5; i <= 5; i++) {
uptr row_shadow_addr = aligned_shadow + i * n_bytes_per_row;
diff --git a/libsanitizer/asan/asan_fake_stack.cpp b/libsanitizer/asan/asan_fake_stack.cpp
index 295e6debc96..1f873fec7d7 100644
--- a/libsanitizer/asan/asan_fake_stack.cpp
+++ b/libsanitizer/asan/asan_fake_stack.cpp
@@ -65,7 +65,7 @@ FakeStack *FakeStack::Create(uptr stack_size_log) {
void FakeStack::Destroy(int tid) {
PoisonAll(0);
if (Verbosity() >= 2) {
- InternalScopedString str(kNumberOfSizeClasses * 50);
+ InternalScopedString str;
for (uptr class_id = 0; class_id < kNumberOfSizeClasses; class_id++)
str.append("%zd: %zd/%zd; ", class_id, hint_position_[class_id],
NumberOfFrames(stack_size_log(), class_id));
diff --git a/libsanitizer/asan/asan_fuchsia.cpp b/libsanitizer/asan/asan_fuchsia.cpp
index 6c61344f87c..b0c7255144a 100644
--- a/libsanitizer/asan/asan_fuchsia.cpp
+++ b/libsanitizer/asan/asan_fuchsia.cpp
@@ -81,7 +81,7 @@ void AsanTSDInit(void (*destructor)(void *tsd)) {
void PlatformTSDDtor(void *tsd) { UNREACHABLE(__func__); }
static inline size_t AsanThreadMmapSize() {
- return RoundUpTo(sizeof(AsanThread), PAGE_SIZE);
+ return RoundUpTo(sizeof(AsanThread), _zx_system_get_page_size());
}
struct AsanThread::InitOptions {
diff --git a/libsanitizer/asan/asan_globals.cpp b/libsanitizer/asan/asan_globals.cpp
index e045c31cd1c..9d7dbc6f264 100644
--- a/libsanitizer/asan/asan_globals.cpp
+++ b/libsanitizer/asan/asan_globals.cpp
@@ -154,6 +154,23 @@ static void CheckODRViolationViaIndicator(const Global *g) {
}
}
+// Check ODR violation for given global G by checking if it's already poisoned.
+// We use this method in case compiler doesn't use private aliases for global
+// variables.
+static void CheckODRViolationViaPoisoning(const Global *g) {
+ if (__asan_region_is_poisoned(g->beg, g->size_with_redzone)) {
+ // This check may not be enough: if the first global is much larger
+ // the entire redzone of the second global may be within the first global.
+ for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) {
+ if (g->beg == l->g->beg &&
+ (flags()->detect_odr_violation >= 2 || g->size != l->g->size) &&
+ !IsODRViolationSuppressed(g->name))
+ ReportODRViolation(g, FindRegistrationSite(g),
+ l->g, FindRegistrationSite(l->g));
+ }
+ }
+}
+
// Clang provides two different ways for global variables protection:
// it can poison the global itself or its private alias. In former
// case we may poison same symbol multiple times, that can help us to
@@ -199,6 +216,8 @@ static void RegisterGlobal(const Global *g) {
// where two globals with the same name are defined in different modules.
if (UseODRIndicator(g))
CheckODRViolationViaIndicator(g);
+ else
+ CheckODRViolationViaPoisoning(g);
}
if (CanPoisonMemory())
PoisonRedZones(*g);
diff --git a/libsanitizer/asan/asan_interceptors.cpp b/libsanitizer/asan/asan_interceptors.cpp
index 4e68b3b0b47..9db7db89fa1 100644
--- a/libsanitizer/asan/asan_interceptors.cpp
+++ b/libsanitizer/asan/asan_interceptors.cpp
@@ -191,20 +191,11 @@ DECLARE_REAL_AND_INTERCEPTOR(void, free, void *)
#include "sanitizer_common/sanitizer_common_syscalls.inc"
#include "sanitizer_common/sanitizer_syscalls_netbsd.inc"
-struct ThreadStartParam {
- atomic_uintptr_t t;
- atomic_uintptr_t is_registered;
-};
-
#if ASAN_INTERCEPT_PTHREAD_CREATE
static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) {
- ThreadStartParam *param = reinterpret_cast<ThreadStartParam *>(arg);
- AsanThread *t = nullptr;
- while ((t = reinterpret_cast<AsanThread *>(
- atomic_load(¶m->t, memory_order_acquire))) == nullptr)
- internal_sched_yield();
+ AsanThread *t = (AsanThread *)arg;
SetCurrentThread(t);
- return t->ThreadStart(GetTid(), ¶m->is_registered);
+ return t->ThreadStart(GetTid());
}
INTERCEPTOR(int, pthread_create, void *thread,
@@ -217,9 +208,11 @@ INTERCEPTOR(int, pthread_create, void *thread,
int detached = 0;
if (attr)
REAL(pthread_attr_getdetachstate)(attr, &detached);
- ThreadStartParam param;
- atomic_store(¶m.t, 0, memory_order_relaxed);
- atomic_store(¶m.is_registered, 0, memory_order_relaxed);
+
+ u32 current_tid = GetCurrentTidOrInvalid();
+ AsanThread *t =
+ AsanThread::Create(start_routine, arg, current_tid, &stack, detached);
+
int result;
{
// Ignore all allocations made by pthread_create: thread stack/TLS may be
@@ -229,21 +222,13 @@ INTERCEPTOR(int, pthread_create, void *thread,
#if CAN_SANITIZE_LEAKS
__lsan::ScopedInterceptorDisabler disabler;
#endif
- result = REAL(pthread_create)(thread, attr, asan_thread_start, ¶m);
+ result = REAL(pthread_create)(thread, attr, asan_thread_start, t);
}
- if (result == 0) {
- u32 current_tid = GetCurrentTidOrInvalid();
- AsanThread *t =
- AsanThread::Create(start_routine, arg, current_tid, &stack, detached);
- atomic_store(¶m.t, reinterpret_cast<uptr>(t), memory_order_release);
- // Wait until the AsanThread object is initialized and the ThreadRegistry
- // entry is in "started" state. One reason for this is that after this
- // interceptor exits, the child thread's stack may be the only thing holding
- // the |arg| pointer. This may cause LSan to report a leak if leak checking
- // happens at a point when the interceptor has already exited, but the stack
- // range for the child thread is not yet known.
- while (atomic_load(¶m.is_registered, memory_order_acquire) == 0)
- internal_sched_yield();
+ if (result != 0) {
+ // If the thread didn't start delete the AsanThread to avoid leaking it.
+ // Note AsanThreadContexts never get destroyed so the AsanThreadContext
+ // that was just created for the AsanThread is wasted.
+ t->Destroy();
}
return result;
}
diff --git a/libsanitizer/asan/asan_interceptors.h b/libsanitizer/asan/asan_interceptors.h
index 56dc34b7d93..e8c58c2dc6b 100644
--- a/libsanitizer/asan/asan_interceptors.h
+++ b/libsanitizer/asan/asan_interceptors.h
@@ -60,7 +60,7 @@ void InitializePlatformInterceptors();
# define ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX 0
#endif
-#if (SANITIZER_LINUX && !SANITIZER_ANDROID) || SANITIZER_SOLARIS
+#if SANITIZER_GLIBC || SANITIZER_SOLARIS
# define ASAN_INTERCEPT_SWAPCONTEXT 1
#else
# define ASAN_INTERCEPT_SWAPCONTEXT 0
@@ -72,7 +72,7 @@ void InitializePlatformInterceptors();
# define ASAN_INTERCEPT_SIGLONGJMP 0
#endif
-#if SANITIZER_LINUX && !SANITIZER_ANDROID
+#if SANITIZER_GLIBC
# define ASAN_INTERCEPT___LONGJMP_CHK 1
#else
# define ASAN_INTERCEPT___LONGJMP_CHK 0
@@ -81,12 +81,7 @@ void InitializePlatformInterceptors();
#if ASAN_HAS_EXCEPTIONS && !SANITIZER_WINDOWS && !SANITIZER_SOLARIS && \
!SANITIZER_NETBSD
# define ASAN_INTERCEPT___CXA_THROW 1
-# if ! defined(ASAN_HAS_CXA_RETHROW_PRIMARY_EXCEPTION) \
- || ASAN_HAS_CXA_RETHROW_PRIMARY_EXCEPTION
-# define ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION 1
-# else
-# define ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION 0
-# endif
+# define ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION 1
# if defined(_GLIBCXX_SJLJ_EXCEPTIONS) || (SANITIZER_IOS && defined(__arm__))
# define ASAN_INTERCEPT__UNWIND_SJLJ_RAISEEXCEPTION 1
# else
@@ -111,7 +106,7 @@ void InitializePlatformInterceptors();
# define ASAN_INTERCEPT_ATEXIT 0
#endif
-#if SANITIZER_LINUX && !SANITIZER_ANDROID
+#if SANITIZER_GLIBC
# define ASAN_INTERCEPT___STRDUP 1
#else
# define ASAN_INTERCEPT___STRDUP 0
@@ -139,10 +134,10 @@ DECLARE_REAL(uptr, strnlen, const char *s, uptr maxlen)
DECLARE_REAL(char*, strstr, const char *s1, const char *s2)
#if !SANITIZER_MAC
-#define ASAN_INTERCEPT_FUNC(name) \
- do { \
- if (!INTERCEPT_FUNCTION(name)) \
- VReport(1, "AddressSanitizer: failed to intercept '%s'\n'", #name); \
+#define ASAN_INTERCEPT_FUNC(name) \
+ do { \
+ if (!INTERCEPT_FUNCTION(name)) \
+ VReport(1, "AddressSanitizer: failed to intercept '%s'\n", #name); \
} while (0)
#define ASAN_INTERCEPT_FUNC_VER(name, ver) \
do { \
diff --git a/libsanitizer/asan/asan_linux.cpp b/libsanitizer/asan/asan_linux.cpp
index fb1a442b3d4..4bcbe5d02e3 100644
--- a/libsanitizer/asan/asan_linux.cpp
+++ b/libsanitizer/asan/asan_linux.cpp
@@ -55,6 +55,7 @@ extern Elf_Dyn _DYNAMIC;
#else
#include <sys/ucontext.h>
#include <link.h>
+extern ElfW(Dyn) _DYNAMIC[];
#endif
// x86-64 FreeBSD 9.2 and older define 'ucontext_t' incorrectly in
@@ -84,7 +85,7 @@ bool IsSystemHeapAddress (uptr addr) { return false; }
void *AsanDoesNotSupportStaticLinkage() {
// This will fail to link with -static.
- return &_DYNAMIC; // defined in link.h
+ return &_DYNAMIC;
}
#if ASAN_PREMAP_SHADOW
diff --git a/libsanitizer/asan/asan_mapping.h b/libsanitizer/asan/asan_mapping.h
index a7136de60d2..455e2364cd0 100644
--- a/libsanitizer/asan/asan_mapping.h
+++ b/libsanitizer/asan/asan_mapping.h
@@ -72,6 +72,13 @@
// || `[0x2000000000, 0x23ffffffff]` || LowShadow ||
// || `[0x0000000000, 0x1fffffffff]` || LowMem ||
//
+// Default Linux/RISCV64 Sv39 mapping:
+// || `[0x1555550000, 0x3fffffffff]` || HighMem ||
+// || `[0x0fffffa000, 0x1555555fff]` || HighShadow ||
+// || `[0x0effffa000, 0x0fffff9fff]` || ShadowGap ||
+// || `[0x0d55550000, 0x0effff9fff]` || LowShadow ||
+// || `[0x0000000000, 0x0d5554ffff]` || LowMem ||
+//
// Default Linux/AArch64 (39-bit VMA) mapping:
// || `[0x2000000000, 0x7fffffffff]` || highmem ||
// || `[0x1400000000, 0x1fffffffff]` || highshadow ||
@@ -79,20 +86,6 @@
// || `[0x1000000000, 0x11ffffffff]` || lowshadow ||
// || `[0x0000000000, 0x0fffffffff]` || lowmem ||
//
-// RISC-V has only 38 bits for task size
-// Low mem size is set with kRiscv64_ShadowOffset64 in
-// compiler-rt/lib/asan/asan_allocator.h and in
-// llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp with
-// kRiscv64_ShadowOffset64, High mem top border is set with
-// GetMaxVirtualAddress() in
-// compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp
-// Default Linux/RISCV64 Sv39/Sv48 mapping:
-// || `[0x000820000000, 0x003fffffffff]` || HighMem ||
-// || `[0x000124000000, 0x00081fffffff]` || HighShadow ||
-// || `[0x000024000000, 0x000123ffffff]` || ShadowGap ||
-// || `[0x000020000000, 0x000023ffffff]` || LowShadow ||
-// || `[0x000000000000, 0x00001fffffff]` || LowMem ||
-//
// Default Linux/AArch64 (42-bit VMA) mapping:
// || `[0x10000000000, 0x3ffffffffff]` || highmem ||
// || `[0x0a000000000, 0x0ffffffffff]` || highshadow ||
@@ -175,10 +168,10 @@ static const u64 kDefaultShadowOffset64 = 1ULL << 44;
static const u64 kDefaultShort64bitShadowOffset =
0x7FFFFFFF & (~0xFFFULL << kDefaultShadowScale); // < 2G.
static const u64 kAArch64_ShadowOffset64 = 1ULL << 36;
-static const u64 kRiscv64_ShadowOffset64 = 0x20000000;
+static const u64 kRiscv64_ShadowOffset64 = 0xd55550000;
static const u64 kMIPS32_ShadowOffset32 = 0x0aaa0000;
static const u64 kMIPS64_ShadowOffset64 = 1ULL << 37;
-static const u64 kPPC64_ShadowOffset64 = 1ULL << 41;
+static const u64 kPPC64_ShadowOffset64 = 1ULL << 44;
static const u64 kSystemZ_ShadowOffset64 = 1ULL << 52;
static const u64 kSPARC64_ShadowOffset64 = 1ULL << 43; // 0x80000000000
static const u64 kFreeBSD_ShadowOffset32 = 1ULL << 30; // 0x40000000
diff --git a/libsanitizer/asan/asan_new_delete.cpp b/libsanitizer/asan/asan_new_delete.cpp
index 5dfcc00fd5d..92a8648452b 100644
--- a/libsanitizer/asan/asan_new_delete.cpp
+++ b/libsanitizer/asan/asan_new_delete.cpp
@@ -45,7 +45,7 @@ COMMENT_EXPORT("??_V@YAXPAX@Z") // operator delete[]
#endif
#undef COMMENT_EXPORT
#else
-#define CXX_OPERATOR_ATTRIBUTE INTERCEPTOR_ATTRIBUTE
+#define CXX_OPERATOR_ATTRIBUTE INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
#endif
using namespace __asan;
diff --git a/libsanitizer/asan/asan_poisoning.cpp b/libsanitizer/asan/asan_poisoning.cpp
index 44f872ef619..fa149ecfde6 100644
--- a/libsanitizer/asan/asan_poisoning.cpp
+++ b/libsanitizer/asan/asan_poisoning.cpp
@@ -364,7 +364,7 @@ void __sanitizer_annotate_contiguous_container(const void *beg_p,
&stack);
}
CHECK_LE(end - beg,
- FIRST_32_SECOND_64(1UL << 30, 1ULL << 34)); // Sanity check.
+ FIRST_32_SECOND_64(1UL << 30, 1ULL << 40)); // Sanity check.
uptr a = RoundDownTo(Min(old_mid, new_mid), granularity);
uptr c = RoundUpTo(Max(old_mid, new_mid), granularity);
diff --git a/libsanitizer/asan/asan_posix.cpp b/libsanitizer/asan/asan_posix.cpp
index d7f19d84654..63ad735f8bb 100644
--- a/libsanitizer/asan/asan_posix.cpp
+++ b/libsanitizer/asan/asan_posix.cpp
@@ -56,7 +56,7 @@ bool PlatformUnpoisonStacks() {
if (signal_stack.ss_flags != SS_ONSTACK)
return false;
- // Since we're on the signal altnerate stack, we cannot find the DEFAULT
+ // Since we're on the signal alternate stack, we cannot find the DEFAULT
// stack bottom using a local variable.
uptr default_bottom, tls_addr, tls_size, stack_size;
GetThreadStackAndTls(/*main=*/false, &default_bottom, &stack_size, &tls_addr,
diff --git a/libsanitizer/asan/asan_rtl.cpp b/libsanitizer/asan/asan_rtl.cpp
index 7b5a929963c..e715d774228 100644
--- a/libsanitizer/asan/asan_rtl.cpp
+++ b/libsanitizer/asan/asan_rtl.cpp
@@ -62,19 +62,9 @@ static void AsanDie() {
}
}
-static void AsanCheckFailed(const char *file, int line, const char *cond,
- u64 v1, u64 v2) {
- Report("AddressSanitizer CHECK failed: %s:%d \"%s\" (0x%zx, 0x%zx)\n", file,
- line, cond, (uptr)v1, (uptr)v2);
-
- // Print a stack trace the first time we come here. Otherwise, we probably
- // failed a CHECK during symbolization.
- static atomic_uint32_t num_calls;
- if (atomic_fetch_add(&num_calls, 1, memory_order_relaxed) == 0) {
- PRINT_CURRENT_STACK_CHECK();
- }
-
- Die();
+static void CheckUnwind() {
+ GET_STACK_TRACE(kStackTraceMax, common_flags()->fast_unwind_on_check);
+ stack.Print();
}
// -------------------------- Globals --------------------- {{{1
@@ -432,7 +422,7 @@ static void AsanInitInternal() {
// Install tool-specific callbacks in sanitizer_common.
AddDieCallback(AsanDie);
- SetCheckFailedCallback(AsanCheckFailed);
+ SetCheckUnwindCallback(CheckUnwind);
SetPrintfAndReportCallback(AppendToErrorMessageBuffer);
__sanitizer_set_report_path(common_flags()->log_path);
@@ -568,7 +558,7 @@ void UnpoisonStack(uptr bottom, uptr top, const char *type) {
type, top, bottom, top - bottom, top - bottom);
return;
}
- PoisonShadow(bottom, top - bottom, 0);
+ PoisonShadow(bottom, RoundUpTo(top - bottom, SHADOW_GRANULARITY), 0);
}
static void UnpoisonDefaultStack() {
diff --git a/libsanitizer/asan/asan_stack.h b/libsanitizer/asan/asan_stack.h
index 47ca85a1644..b9575d2f427 100644
--- a/libsanitizer/asan/asan_stack.h
+++ b/libsanitizer/asan/asan_stack.h
@@ -54,9 +54,6 @@ u32 GetMallocContextSize();
#define GET_STACK_TRACE_FATAL_HERE \
GET_STACK_TRACE(kStackTraceMax, common_flags()->fast_unwind_on_fatal)
-#define GET_STACK_TRACE_CHECK_HERE \
- GET_STACK_TRACE(kStackTraceMax, common_flags()->fast_unwind_on_check)
-
#define GET_STACK_TRACE_THREAD \
GET_STACK_TRACE(kStackTraceMax, true)
@@ -71,10 +68,4 @@ u32 GetMallocContextSize();
stack.Print(); \
}
-#define PRINT_CURRENT_STACK_CHECK() \
- { \
- GET_STACK_TRACE_CHECK_HERE; \
- stack.Print(); \
- }
-
#endif // ASAN_STACK_H
diff --git a/libsanitizer/asan/asan_thread.cpp b/libsanitizer/asan/asan_thread.cpp
index fb09af0ecca..9c3c86f5735 100644
--- a/libsanitizer/asan/asan_thread.cpp
+++ b/libsanitizer/asan/asan_thread.cpp
@@ -100,18 +100,27 @@ void AsanThread::Destroy() {
int tid = this->tid();
VReport(1, "T%d exited\n", tid);
- malloc_storage().CommitBack();
- if (common_flags()->use_sigaltstack) UnsetAlternateSignalStack();
- asanThreadRegistry().FinishThread(tid);
- FlushToDeadThreadStats(&stats_);
- // We also clear the shadow on thread destruction because
- // some code may still be executing in later TSD destructors
- // and we don't want it to have any poisoned stack.
- ClearShadowForThreadStackAndTLS();
- DeleteFakeStack(tid);
+ bool was_running =
+ (asanThreadRegistry().FinishThread(tid) == ThreadStatusRunning);
+ if (was_running) {
+ if (AsanThread *thread = GetCurrentThread())
+ CHECK_EQ(this, thread);
+ malloc_storage().CommitBack();
+ if (common_flags()->use_sigaltstack)
+ UnsetAlternateSignalStack();
+ FlushToDeadThreadStats(&stats_);
+ // We also clear the shadow on thread destruction because
+ // some code may still be executing in later TSD destructors
+ // and we don't want it to have any poisoned stack.
+ ClearShadowForThreadStackAndTLS();
+ DeleteFakeStack(tid);
+ } else {
+ CHECK_NE(this, GetCurrentThread());
+ }
uptr size = RoundUpTo(sizeof(AsanThread), GetPageSizeCached());
UnmapOrDie(this, size);
- DTLS_Destroy();
+ if (was_running)
+ DTLS_Destroy();
}
void AsanThread::StartSwitchFiber(FakeStack **fake_stack_save, uptr bottom,
@@ -219,7 +228,7 @@ FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() {
}
void AsanThread::Init(const InitOptions *options) {
- DCHECK_NE(tid(), ThreadRegistry::kUnknownTid);
+ DCHECK_NE(tid(), kInvalidTid);
next_stack_top_ = next_stack_bottom_ = 0;
atomic_store(&stack_switching_, false, memory_order_release);
CHECK_EQ(this->stack_size(), 0U);
@@ -253,12 +262,9 @@ void AsanThread::Init(const InitOptions *options) {
// SetThreadStackAndTls.
#if !SANITIZER_FUCHSIA && !SANITIZER_RTEMS
-thread_return_t AsanThread::ThreadStart(
- tid_t os_id, atomic_uintptr_t *signal_thread_is_registered) {
+thread_return_t AsanThread::ThreadStart(tid_t os_id) {
Init();
asanThreadRegistry().StartThread(tid(), os_id, ThreadType::Regular, nullptr);
- if (signal_thread_is_registered)
- atomic_store(signal_thread_is_registered, 1, memory_order_release);
if (common_flags()->use_sigaltstack) SetAlternateSignalStack();
@@ -285,11 +291,10 @@ thread_return_t AsanThread::ThreadStart(
AsanThread *CreateMainThread() {
AsanThread *main_thread = AsanThread::Create(
- /* start_routine */ nullptr, /* arg */ nullptr, /* parent_tid */ 0,
+ /* start_routine */ nullptr, /* arg */ nullptr, /* parent_tid */ kMainTid,
/* stack */ nullptr, /* detached */ true);
SetCurrentThread(main_thread);
- main_thread->ThreadStart(internal_getpid(),
- /* signal_thread_is_registered */ nullptr);
+ main_thread->ThreadStart(internal_getpid());
return main_thread;
}
@@ -300,9 +305,9 @@ void AsanThread::SetThreadStackAndTls(const InitOptions *options) {
DCHECK_EQ(options, nullptr);
uptr tls_size = 0;
uptr stack_size = 0;
- GetThreadStackAndTls(tid() == 0, &stack_bottom_, &stack_size, &tls_begin_,
- &tls_size);
- stack_top_ = stack_bottom_ + stack_size;
+ GetThreadStackAndTls(tid() == kMainTid, &stack_bottom_, &stack_size,
+ &tls_begin_, &tls_size);
+ stack_top_ = RoundDownTo(stack_bottom_ + stack_size, SHADOW_GRANULARITY);
tls_end_ = tls_begin_ + tls_size;
dtls_ = DTLS_Get();
@@ -426,7 +431,7 @@ AsanThread *GetCurrentThread() {
// address. We are not entirely sure that we have correct main thread
// limits, so only do this magic on Android, and only if the found thread
// is the main thread.
- AsanThreadContext *tctx = GetThreadContextByTidLocked(0);
+ AsanThreadContext *tctx = GetThreadContextByTidLocked(kMainTid);
if (tctx && ThreadStackContainsAddress(tctx, &context)) {
SetCurrentThread(tctx->thread);
return tctx->thread;
@@ -463,7 +468,7 @@ AsanThread *FindThreadByStackAddress(uptr addr) {
void EnsureMainThreadIDIsCorrect() {
AsanThreadContext *context =
reinterpret_cast<AsanThreadContext *>(AsanTSDGet());
- if (context && (context->tid == 0))
+ if (context && (context->tid == kMainTid))
context->os_id = GetTid();
}
diff --git a/libsanitizer/asan/asan_thread.h b/libsanitizer/asan/asan_thread.h
index ea58de4216a..200069ce0dd 100644
--- a/libsanitizer/asan/asan_thread.h
+++ b/libsanitizer/asan/asan_thread.h
@@ -28,7 +28,6 @@ struct DTLS;
namespace __asan {
-const u32 kInvalidTid = 0xffffff; // Must fit into 24 bits.
const u32 kMaxNumberOfThreads = (1 << 22); // 4M
class AsanThread;
@@ -69,8 +68,7 @@ class AsanThread {
struct InitOptions;
void Init(const InitOptions *options = nullptr);
- thread_return_t ThreadStart(tid_t os_id,
- atomic_uintptr_t *signal_thread_is_registered);
+ thread_return_t ThreadStart(tid_t os_id);
uptr stack_top();
uptr stack_bottom();
@@ -132,6 +130,8 @@ class AsanThread {
void *extra_spill_area() { return &extra_spill_area_; }
+ void *get_arg() { return arg_; }
+
private:
// NOTE: There is no AsanThread constructor. It is allocated
// via mmap() and *must* be valid in zero-initialized state.
diff --git a/libsanitizer/asan/asan_win.cpp b/libsanitizer/asan/asan_win.cpp
index 8044ae16ff9..1577c83cf99 100644
--- a/libsanitizer/asan/asan_win.cpp
+++ b/libsanitizer/asan/asan_win.cpp
@@ -134,7 +134,7 @@ INTERCEPTOR(int, _except_handler4, void *a, void *b, void *c, void *d) {
static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) {
AsanThread *t = (AsanThread *)arg;
SetCurrentThread(t);
- return t->ThreadStart(GetTid(), /* signal_thread_is_registered */ nullptr);
+ return t->ThreadStart(GetTid());
}
INTERCEPTOR_WINAPI(HANDLE, CreateThread, LPSECURITY_ATTRIBUTES security,
diff --git a/libsanitizer/builtins/assembly.h b/libsanitizer/builtins/assembly.h
index f437cb87f60..9c015059af5 100644
--- a/libsanitizer/builtins/assembly.h
+++ b/libsanitizer/builtins/assembly.h
@@ -14,8 +14,8 @@
#ifndef COMPILERRT_ASSEMBLY_H
#define COMPILERRT_ASSEMBLY_H
-#if defined(__POWERPC__) || defined(__powerpc__) || defined(__ppc__)
-#define SEPARATOR @
+#if defined(__APPLE__) && defined(__aarch64__)
+#define SEPARATOR %%
#else
#define SEPARATOR ;
#endif
@@ -35,14 +35,14 @@
#define HIDDEN(name) .hidden name
#define LOCAL_LABEL(name) .L_##name
#define FILE_LEVEL_DIRECTIVE
-#if defined(__arm__)
+#if defined(__arm__) || defined(__aarch64__)
#define SYMBOL_IS_FUNC(name) .type name,%function
#else
#define SYMBOL_IS_FUNC(name) .type name,@function
#endif
#define CONST_SECTION .section .rodata
-#if defined(__GNU__) || defined(__FreeBSD__) || defined(__Fuchsia__) || \
+#if defined(__GNU__) || defined(__FreeBSD__) || defined(__Fuchsia__) || \
defined(__linux__)
#define NO_EXEC_STACK_DIRECTIVE .section .note.GNU-stack,"",%progbits
#else
@@ -65,6 +65,68 @@
#endif
+#if defined(__arm__) || defined(__aarch64__)
+#define FUNC_ALIGN \
+ .text SEPARATOR \
+ .balign 16 SEPARATOR
+#else
+#define FUNC_ALIGN
+#endif
+
+// BTI and PAC gnu property note
+#define NT_GNU_PROPERTY_TYPE_0 5
+#define GNU_PROPERTY_AARCH64_FEATURE_1_AND 0xc0000000
+#define GNU_PROPERTY_AARCH64_FEATURE_1_BTI 1
+#define GNU_PROPERTY_AARCH64_FEATURE_1_PAC 2
+
+#if defined(__ARM_FEATURE_BTI_DEFAULT)
+#define BTI_FLAG GNU_PROPERTY_AARCH64_FEATURE_1_BTI
+#else
+#define BTI_FLAG 0
+#endif
+
+#if __ARM_FEATURE_PAC_DEFAULT & 3
+#define PAC_FLAG GNU_PROPERTY_AARCH64_FEATURE_1_PAC
+#else
+#define PAC_FLAG 0
+#endif
+
+#define GNU_PROPERTY(type, value) \
+ .pushsection .note.gnu.property, "a" SEPARATOR \
+ .p2align 3 SEPARATOR \
+ .word 4 SEPARATOR \
+ .word 16 SEPARATOR \
+ .word NT_GNU_PROPERTY_TYPE_0 SEPARATOR \
+ .asciz "GNU" SEPARATOR \
+ .word type SEPARATOR \
+ .word 4 SEPARATOR \
+ .word value SEPARATOR \
+ .word 0 SEPARATOR \
+ .popsection
+
+#if BTI_FLAG != 0
+#define BTI_C hint #34
+#define BTI_J hint #36
+#else
+#define BTI_C
+#define BTI_J
+#endif
+
+#if (BTI_FLAG | PAC_FLAG) != 0
+#define GNU_PROPERTY_BTI_PAC \
+ GNU_PROPERTY(GNU_PROPERTY_AARCH64_FEATURE_1_AND, BTI_FLAG | PAC_FLAG)
+#else
+#define GNU_PROPERTY_BTI_PAC
+#endif
+
+#if defined(__clang__) || defined(__GCC_HAVE_DWARF2_CFI_ASM)
+#define CFI_START .cfi_startproc
+#define CFI_END .cfi_endproc
+#else
+#define CFI_START
+#define CFI_END
+#endif
+
#if defined(__arm__)
// Determine actual [ARM][THUMB[1][2]] ISA using compiler predefined macros:
@@ -131,15 +193,24 @@
#define DEFINE_CODE_STATE
#endif
-#define GLUE2(a, b) a##b
-#define GLUE(a, b) GLUE2(a, b)
+#define GLUE2_(a, b) a##b
+#define GLUE(a, b) GLUE2_(a, b)
+#define GLUE2(a, b) GLUE2_(a, b)
+#define GLUE3_(a, b, c) a##b##c
+#define GLUE3(a, b, c) GLUE3_(a, b, c)
+#define GLUE4_(a, b, c, d) a##b##c##d
+#define GLUE4(a, b, c, d) GLUE4_(a, b, c, d)
+
#define SYMBOL_NAME(name) GLUE(__USER_LABEL_PREFIX__, name)
#ifdef VISIBILITY_HIDDEN
#define DECLARE_SYMBOL_VISIBILITY(name) \
HIDDEN(SYMBOL_NAME(name)) SEPARATOR
+#define DECLARE_SYMBOL_VISIBILITY_UNMANGLED(name) \
+ HIDDEN(name) SEPARATOR
#else
#define DECLARE_SYMBOL_VISIBILITY(name)
+#define DECLARE_SYMBOL_VISIBILITY_UNMANGLED(name)
#endif
#define DEFINE_COMPILERRT_FUNCTION(name) \
@@ -177,6 +248,16 @@
DECLARE_FUNC_ENCODING \
name:
+#define DEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(name) \
+ DEFINE_CODE_STATE \
+ FUNC_ALIGN \
+ .globl name SEPARATOR \
+ SYMBOL_IS_FUNC(name) SEPARATOR \
+ DECLARE_SYMBOL_VISIBILITY_UNMANGLED(name) SEPARATOR \
+ CFI_START SEPARATOR \
+ DECLARE_FUNC_ENCODING \
+ name: SEPARATOR BTI_C
+
#define DEFINE_COMPILERRT_FUNCTION_ALIAS(name, target) \
.globl SYMBOL_NAME(name) SEPARATOR \
SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \
@@ -193,8 +274,13 @@
#ifdef __ELF__
#define END_COMPILERRT_FUNCTION(name) \
.size SYMBOL_NAME(name), . - SYMBOL_NAME(name)
+#define END_COMPILERRT_OUTLINE_FUNCTION(name) \
+ CFI_END SEPARATOR \
+ .size SYMBOL_NAME(name), . - SYMBOL_NAME(name)
#else
#define END_COMPILERRT_FUNCTION(name)
+#define END_COMPILERRT_OUTLINE_FUNCTION(name) \
+ CFI_END
#endif
#endif // COMPILERRT_ASSEMBLY_H
diff --git a/libsanitizer/hwasan/hwasan.cpp b/libsanitizer/hwasan/hwasan.cpp
index c5322110cb6..8d6c25261b8 100644
--- a/libsanitizer/hwasan/hwasan.cpp
+++ b/libsanitizer/hwasan/hwasan.cpp
@@ -128,16 +128,11 @@ static void InitializeFlags() {
if (common_flags()->help) parser.PrintFlagDescriptions();
}
-static void HWAsanCheckFailed(const char *file, int line, const char *cond,
- u64 v1, u64 v2) {
- Report("HWAddressSanitizer CHECK failed: %s:%d \"%s\" (0x%zx, 0x%zx)\n", file,
- line, cond, (uptr)v1, (uptr)v2);
- PRINT_CURRENT_STACK_CHECK();
- Die();
+static void CheckUnwind() {
+ GET_FATAL_STACK_TRACE_PC_BP(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME());
+ stack.Print();
}
-static constexpr uptr kMemoryUsageBufferSize = 4096;
-
static void HwasanFormatMemoryUsage(InternalScopedString &s) {
HwasanThreadList &thread_list = hwasanThreadList();
auto thread_stats = thread_list.GetThreadStats();
@@ -155,6 +150,8 @@ static void HwasanFormatMemoryUsage(InternalScopedString &s) {
}
#if SANITIZER_ANDROID
+static constexpr uptr kMemoryUsageBufferSize = 4096;
+
static char *memory_usage_buffer = nullptr;
static void InitMemoryUsage() {
@@ -171,7 +168,7 @@ void UpdateMemoryUsage() {
return;
if (!memory_usage_buffer)
InitMemoryUsage();
- InternalScopedString s(kMemoryUsageBufferSize);
+ InternalScopedString s;
HwasanFormatMemoryUsage(s);
internal_strncpy(memory_usage_buffer, s.data(), kMemoryUsageBufferSize - 1);
memory_usage_buffer[kMemoryUsageBufferSize - 1] = '\0';
@@ -271,7 +268,7 @@ void __hwasan_init() {
InitializeFlags();
// Install tool-specific callbacks in sanitizer_common.
- SetCheckFailedCallback(HWAsanCheckFailed);
+ SetCheckUnwindCallback(CheckUnwind);
__sanitizer_set_report_path(common_flags()->log_path);
@@ -493,7 +490,7 @@ extern "C" void *__hwasan_extra_spill_area() {
}
void __hwasan_print_memory_usage() {
- InternalScopedString s(kMemoryUsageBufferSize);
+ InternalScopedString s;
HwasanFormatMemoryUsage(s);
Printf("%s\n", s.data());
}
diff --git a/libsanitizer/hwasan/hwasan.h b/libsanitizer/hwasan/hwasan.h
index d4521efd089..8515df559f3 100644
--- a/libsanitizer/hwasan/hwasan.h
+++ b/libsanitizer/hwasan/hwasan.h
@@ -14,11 +14,12 @@
#ifndef HWASAN_H
#define HWASAN_H
+#include "hwasan_flags.h"
+#include "hwasan_interface_internal.h"
+#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_flags.h"
#include "sanitizer_common/sanitizer_internal_defs.h"
#include "sanitizer_common/sanitizer_stacktrace.h"
-#include "hwasan_interface_internal.h"
-#include "hwasan_flags.h"
#include "ubsan/ubsan_platform.h"
#ifndef HWASAN_CONTAINS_UBSAN
@@ -35,10 +36,31 @@
typedef u8 tag_t;
+#if defined(__x86_64__)
+// Tags are done in middle bits using userspace aliasing.
+constexpr unsigned kAddressTagShift = 39;
+constexpr unsigned kTagBits = 3;
+
+// The alias region is placed next to the shadow so the upper bits of all
+// taggable addresses matches the upper bits of the shadow base. This shift
+// value determines which upper bits must match. It has a floor of 44 since the
+// shadow is always 8TB.
+// TODO(morehouse): In alias mode we can shrink the shadow and use a
+// simpler/faster shadow calculation.
+constexpr unsigned kTaggableRegionCheckShift =
+ __sanitizer::Max(kAddressTagShift + kTagBits + 1U, 44U);
+#else
// TBI (Top Byte Ignore) feature of AArch64: bits [63:56] are ignored in address
// translation and can be used to store a tag.
-const unsigned kAddressTagShift = 56;
-const uptr kAddressTagMask = 0xFFUL << kAddressTagShift;
+constexpr unsigned kAddressTagShift = 56;
+constexpr unsigned kTagBits = 8;
+#endif // defined(__x86_64__)
+
+// Mask for extracting tag bits from the lower 8 bits.
+constexpr uptr kTagMask = (1UL << kTagBits) - 1;
+
+// Mask for extracting tag bits from full pointers.
+constexpr uptr kAddressTagMask = kTagMask << kAddressTagShift;
// Minimal alignment of the shadow base address. Determines the space available
// for threads and stack histories. This is an ABI constant.
@@ -50,7 +72,7 @@ const unsigned kRecordFPLShift = 4;
const unsigned kRecordFPModulus = 1 << (64 - kRecordFPShift + kRecordFPLShift);
static inline tag_t GetTagFromPointer(uptr p) {
- return p >> kAddressTagShift;
+ return (p >> kAddressTagShift) & kTagMask;
}
static inline uptr UntagAddr(uptr tagged_addr) {
@@ -105,15 +127,6 @@ void InstallAtExitHandler();
if (hwasan_inited) \
stack.Unwind(pc, bp, nullptr, common_flags()->fast_unwind_on_fatal)
-#define GET_FATAL_STACK_TRACE_HERE \
- GET_FATAL_STACK_TRACE_PC_BP(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME())
-
-#define PRINT_CURRENT_STACK_CHECK() \
- { \
- GET_FATAL_STACK_TRACE_HERE; \
- stack.Print(); \
- }
-
void HwasanTSDInit();
void HwasanTSDThreadInit();
diff --git a/libsanitizer/hwasan/hwasan_allocator.cpp b/libsanitizer/hwasan/hwasan_allocator.cpp
index 0b6b7347892..a6fc794082a 100644
--- a/libsanitizer/hwasan/hwasan_allocator.cpp
+++ b/libsanitizer/hwasan/hwasan_allocator.cpp
@@ -29,8 +29,8 @@ static AllocatorCache fallback_allocator_cache;
static SpinMutex fallback_mutex;
static atomic_uint8_t hwasan_allocator_tagging_enabled;
-static const tag_t kFallbackAllocTag = 0xBB;
-static const tag_t kFallbackFreeTag = 0xBC;
+static constexpr tag_t kFallbackAllocTag = 0xBB & kTagMask;
+static constexpr tag_t kFallbackFreeTag = 0xBC;
enum RightAlignMode {
kRightAlignNever,
@@ -84,7 +84,8 @@ void HwasanAllocatorInit() {
atomic_store_relaxed(&hwasan_allocator_tagging_enabled,
!flags()->disable_allocator_tagging);
SetAllocatorMayReturnNull(common_flags()->allocator_may_return_null);
- allocator.Init(common_flags()->allocator_release_to_os_interval_ms);
+ allocator.Init(common_flags()->allocator_release_to_os_interval_ms,
+ kAliasRegionStart);
for (uptr i = 0; i < sizeof(tail_magic); i++)
tail_magic[i] = GetCurrentThread()->GenerateRandomTag();
}
@@ -148,7 +149,8 @@ static void *HwasanAllocate(StackTrace *stack, uptr orig_size, uptr alignment,
// Tagging can only be skipped when both tag_in_malloc and tag_in_free are
// false. When tag_in_malloc = false and tag_in_free = true malloc needs to
// retag to 0.
- if ((flags()->tag_in_malloc || flags()->tag_in_free) &&
+ if (InTaggableRegion(reinterpret_cast<uptr>(user_ptr)) &&
+ (flags()->tag_in_malloc || flags()->tag_in_free) &&
atomic_load_relaxed(&hwasan_allocator_tagging_enabled)) {
if (flags()->tag_in_malloc && malloc_bisect(stack, orig_size)) {
tag_t tag = t ? t->GenerateRandomTag() : kFallbackAllocTag;
@@ -175,6 +177,8 @@ static void *HwasanAllocate(StackTrace *stack, uptr orig_size, uptr alignment,
static bool PointerAndMemoryTagsMatch(void *tagged_ptr) {
CHECK(tagged_ptr);
uptr tagged_uptr = reinterpret_cast<uptr>(tagged_ptr);
+ if (!InTaggableRegion(tagged_uptr))
+ return true;
tag_t mem_tag = *reinterpret_cast<tag_t *>(
MemToShadow(reinterpret_cast<uptr>(UntagPtr(tagged_ptr))));
return PossiblyShortTagMatches(mem_tag, tagged_uptr, 1);
@@ -187,7 +191,9 @@ static void HwasanDeallocate(StackTrace *stack, void *tagged_ptr) {
if (!PointerAndMemoryTagsMatch(tagged_ptr))
ReportInvalidFree(stack, reinterpret_cast<uptr>(tagged_ptr));
- void *untagged_ptr = UntagPtr(tagged_ptr);
+ void *untagged_ptr = InTaggableRegion(reinterpret_cast<uptr>(tagged_ptr))
+ ? UntagPtr(tagged_ptr)
+ : tagged_ptr;
void *aligned_ptr = reinterpret_cast<void *>(
RoundDownTo(reinterpret_cast<uptr>(untagged_ptr), kShadowAlignment));
Metadata *meta =
@@ -219,10 +225,14 @@ static void HwasanDeallocate(StackTrace *stack, void *tagged_ptr) {
Min(TaggedSize(orig_size), (uptr)flags()->max_free_fill_size);
internal_memset(aligned_ptr, flags()->free_fill_byte, fill_size);
}
- if (flags()->tag_in_free && malloc_bisect(stack, 0) &&
- atomic_load_relaxed(&hwasan_allocator_tagging_enabled))
+ if (InTaggableRegion(reinterpret_cast<uptr>(tagged_ptr)) &&
+ flags()->tag_in_free && malloc_bisect(stack, 0) &&
+ atomic_load_relaxed(&hwasan_allocator_tagging_enabled)) {
+ // Always store full 8-bit tags on free to maximize UAF detection.
+ tag_t tag = t ? t->GenerateRandomTag(/*num_bits=*/8) : kFallbackFreeTag;
TagMemoryAligned(reinterpret_cast<uptr>(aligned_ptr), TaggedSize(orig_size),
- t ? t->GenerateRandomTag() : kFallbackFreeTag);
+ tag);
+ }
if (t) {
allocator.Deallocate(t->allocator_cache(), aligned_ptr);
if (auto *ha = t->heap_allocations())
@@ -365,7 +375,7 @@ int hwasan_posix_memalign(void **memptr, uptr alignment, uptr size,
// OOM error is already taken care of by HwasanAllocate.
return errno_ENOMEM;
CHECK(IsAligned((uptr)ptr, alignment));
- *(void **)UntagPtr(memptr) = ptr;
+ *memptr = ptr;
return 0;
}
diff --git a/libsanitizer/hwasan/hwasan_allocator.h b/libsanitizer/hwasan/hwasan_allocator.h
index 43670a6a3fb..03bbcff3f0f 100644
--- a/libsanitizer/hwasan/hwasan_allocator.h
+++ b/libsanitizer/hwasan/hwasan_allocator.h
@@ -13,13 +13,15 @@
#ifndef HWASAN_ALLOCATOR_H
#define HWASAN_ALLOCATOR_H
+#include "hwasan.h"
+#include "hwasan_interface_internal.h"
+#include "hwasan_poisoning.h"
#include "sanitizer_common/sanitizer_allocator.h"
#include "sanitizer_common/sanitizer_allocator_checks.h"
#include "sanitizer_common/sanitizer_allocator_interface.h"
#include "sanitizer_common/sanitizer_allocator_report.h"
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_ring_buffer.h"
-#include "hwasan_poisoning.h"
#if !defined(__aarch64__) && !defined(__x86_64__)
#error Unsupported platform
@@ -55,7 +57,12 @@ static const uptr kMaxAllowedMallocSize = 1UL << 40; // 1T
struct AP64 {
static const uptr kSpaceBeg = ~0ULL;
+
+#if defined(__x86_64__)
+ static const uptr kSpaceSize = 1ULL << kAddressTagShift;
+#else
static const uptr kSpaceSize = 0x2000000000ULL;
+#endif
static const uptr kMetadataSize = sizeof(Metadata);
typedef __sanitizer::VeryDenseSizeClassMap SizeClassMap;
using AddressSpaceView = LocalAddressSpaceView;
@@ -102,6 +109,16 @@ typedef RingBuffer<HeapAllocationRecord> HeapAllocationsRingBuffer;
void GetAllocatorStats(AllocatorStatCounters s);
+inline bool InTaggableRegion(uptr addr) {
+#if defined(__x86_64__)
+ // Aliases are mapped next to shadow so that the upper bits match the shadow
+ // base.
+ return (addr >> kTaggableRegionCheckShift) ==
+ (__hwasan_shadow_memory_dynamic_address >> kTaggableRegionCheckShift);
+#endif
+ return true;
+}
+
} // namespace __hwasan
#endif // HWASAN_ALLOCATOR_H
diff --git a/libsanitizer/hwasan/hwasan_checks.h b/libsanitizer/hwasan/hwasan_checks.h
index a8de0fef20f..ab543ea88be 100644
--- a/libsanitizer/hwasan/hwasan_checks.h
+++ b/libsanitizer/hwasan/hwasan_checks.h
@@ -13,6 +13,7 @@
#ifndef HWASAN_CHECKS_H
#define HWASAN_CHECKS_H
+#include "hwasan_allocator.h"
#include "hwasan_mapping.h"
#include "sanitizer_common/sanitizer_common.h"
@@ -81,6 +82,8 @@ enum class AccessType { Load, Store };
template <ErrorAction EA, AccessType AT, unsigned LogSize>
__attribute__((always_inline, nodebug)) static void CheckAddress(uptr p) {
+ if (!InTaggableRegion(p))
+ return;
uptr ptr_raw = p & ~kAddressTagMask;
tag_t mem_tag = *(tag_t *)MemToShadow(ptr_raw);
if (UNLIKELY(!PossiblyShortTagMatches(mem_tag, p, 1 << LogSize))) {
@@ -94,7 +97,7 @@ __attribute__((always_inline, nodebug)) static void CheckAddress(uptr p) {
template <ErrorAction EA, AccessType AT>
__attribute__((always_inline, nodebug)) static void CheckAddressSized(uptr p,
uptr sz) {
- if (sz == 0)
+ if (sz == 0 || !InTaggableRegion(p))
return;
tag_t ptr_tag = GetTagFromPointer(p);
uptr ptr_raw = p & ~kAddressTagMask;
diff --git a/libsanitizer/hwasan/hwasan_dynamic_shadow.cpp b/libsanitizer/hwasan/hwasan_dynamic_shadow.cpp
index 12730b29bae..f53276e330d 100644
--- a/libsanitizer/hwasan/hwasan_dynamic_shadow.cpp
+++ b/libsanitizer/hwasan/hwasan_dynamic_shadow.cpp
@@ -12,15 +12,17 @@
///
//===----------------------------------------------------------------------===//
-#include "hwasan.h"
#include "hwasan_dynamic_shadow.h"
-#include "hwasan_mapping.h"
-#include "sanitizer_common/sanitizer_common.h"
-#include "sanitizer_common/sanitizer_posix.h"
#include <elf.h>
#include <link.h>
+#include "hwasan.h"
+#include "hwasan_mapping.h"
+#include "hwasan_thread_list.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_posix.h"
+
// The code in this file needs to run in an unrelocated binary. It should not
// access any external symbol, including its own non-hidden globals.
@@ -117,6 +119,12 @@ namespace __hwasan {
void InitShadowGOT() {}
uptr FindDynamicShadowStart(uptr shadow_size_bytes) {
+#if defined(__x86_64__)
+ constexpr uptr kAliasSize = 1ULL << kAddressTagShift;
+ constexpr uptr kNumAliases = 1ULL << kTagBits;
+ return MapDynamicShadowAndAliases(shadow_size_bytes, kAliasSize, kNumAliases,
+ RingBufferSize());
+#endif
return MapDynamicShadow(shadow_size_bytes, kShadowScale, kShadowBaseAlignment,
kHighMemEnd);
}
diff --git a/libsanitizer/hwasan/hwasan_flags.h b/libsanitizer/hwasan/hwasan_flags.h
index 0a6998f675d..b17750158d0 100644
--- a/libsanitizer/hwasan/hwasan_flags.h
+++ b/libsanitizer/hwasan/hwasan_flags.h
@@ -12,6 +12,8 @@
#ifndef HWASAN_FLAGS_H
#define HWASAN_FLAGS_H
+#include "sanitizer_common/sanitizer_internal_defs.h"
+
namespace __hwasan {
struct Flags {
diff --git a/libsanitizer/hwasan/hwasan_flags.inc b/libsanitizer/hwasan/hwasan_flags.inc
index 8e431d9c4ff..18ea47f981b 100644
--- a/libsanitizer/hwasan/hwasan_flags.inc
+++ b/libsanitizer/hwasan/hwasan_flags.inc
@@ -72,3 +72,12 @@ HWASAN_FLAG(uptr, malloc_bisect_right, 0,
HWASAN_FLAG(bool, malloc_bisect_dump, false,
"Print all allocations within [malloc_bisect_left, "
"malloc_bisect_right] range ")
+
+
+// Exit if we fail to enable the AArch64 kernel ABI relaxation which allows
+// tagged pointers in syscalls. This is the default, but being able to disable
+// that behaviour is useful for running the testsuite on more platforms (the
+// testsuite can run since we manually ensure any pointer arguments to syscalls
+// are untagged before the call.
+HWASAN_FLAG(bool, fail_without_syscall_abi, true,
+ "Exit if fail to request relaxed syscall ABI.")
diff --git a/libsanitizer/hwasan/hwasan_interceptors.cpp b/libsanitizer/hwasan/hwasan_interceptors.cpp
index 44e569ee6d7..ad67e2787d3 100644
--- a/libsanitizer/hwasan/hwasan_interceptors.cpp
+++ b/libsanitizer/hwasan/hwasan_interceptors.cpp
@@ -221,8 +221,7 @@ INTERCEPTOR(int, pthread_create, void *th, void *attr, void *(*callback)(void*),
ThreadStartArg *A = reinterpret_cast<ThreadStartArg *> (MmapOrDie(
GetPageSizeCached(), "pthread_create"));
*A = {callback, param};
- int res = REAL(pthread_create)(UntagPtr(th), UntagPtr(attr),
- &HwasanThreadStartFunc, A);
+ int res = REAL(pthread_create)(th, attr, &HwasanThreadStartFunc, A);
return res;
}
diff --git a/libsanitizer/hwasan/hwasan_interceptors_vfork.S b/libsanitizer/hwasan/hwasan_interceptors_vfork.S
index 23d565936d8..fd20825e3da 100644
--- a/libsanitizer/hwasan/hwasan_interceptors_vfork.S
+++ b/libsanitizer/hwasan/hwasan_interceptors_vfork.S
@@ -1,4 +1,5 @@
#include "sanitizer_common/sanitizer_asm.h"
+#include "builtins/assembly.h"
#if defined(__linux__) && HWASAN_WITH_INTERCEPTORS
#define COMMON_INTERCEPTOR_SPILL_AREA __hwasan_extra_spill_area
@@ -9,3 +10,5 @@
#endif
NO_EXEC_STACK_DIRECTIVE
+
+GNU_PROPERTY_BTI_PAC
diff --git a/libsanitizer/hwasan/hwasan_interface_internal.h b/libsanitizer/hwasan/hwasan_interface_internal.h
index aedda317497..25c0f94fe51 100644
--- a/libsanitizer/hwasan/hwasan_interface_internal.h
+++ b/libsanitizer/hwasan/hwasan_interface_internal.h
@@ -222,6 +222,9 @@ SANITIZER_INTERFACE_ATTRIBUTE
void *__hwasan_memset(void *s, int c, uptr n);
SANITIZER_INTERFACE_ATTRIBUTE
void *__hwasan_memmove(void *dest, const void *src, uptr n);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __hwasan_set_error_report_callback(void (*callback)(const char *));
} // extern "C"
#endif // HWASAN_INTERFACE_INTERNAL_H
diff --git a/libsanitizer/hwasan/hwasan_linux.cpp b/libsanitizer/hwasan/hwasan_linux.cpp
index e99926d355c..8ce0ff7da95 100644
--- a/libsanitizer/hwasan/hwasan_linux.cpp
+++ b/libsanitizer/hwasan/hwasan_linux.cpp
@@ -76,6 +76,8 @@ uptr kHighShadowEnd;
uptr kHighMemStart;
uptr kHighMemEnd;
+uptr kAliasRegionStart; // Always 0 on non-x86.
+
static void PrintRange(uptr start, uptr end, const char *name) {
Printf("|| [%p, %p] || %.*s ||\n", (void *)start, (void *)end, 10, name);
}
@@ -119,9 +121,11 @@ void InitPrctl() {
#define PR_GET_TAGGED_ADDR_CTRL 56
#define PR_TAGGED_ADDR_ENABLE (1UL << 0)
// Check we're running on a kernel that can use the tagged address ABI.
- if (internal_prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0) == (uptr)-1 &&
- errno == EINVAL) {
-#if SANITIZER_ANDROID
+ int local_errno = 0;
+ if (internal_iserror(internal_prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0),
+ &local_errno) &&
+ local_errno == EINVAL) {
+#if SANITIZER_ANDROID || defined(__x86_64__)
// Some older Android kernels have the tagged pointer ABI on
// unconditionally, and hence don't have the tagged-addr prctl while still
// allow the ABI.
@@ -129,17 +133,20 @@ void InitPrctl() {
// case.
return;
#else
- Printf(
- "FATAL: "
- "HWAddressSanitizer requires a kernel with tagged address ABI.\n");
- Die();
+ if (flags()->fail_without_syscall_abi) {
+ Printf(
+ "FATAL: "
+ "HWAddressSanitizer requires a kernel with tagged address ABI.\n");
+ Die();
+ }
#endif
}
// Turn on the tagged address ABI.
- if (internal_prctl(PR_SET_TAGGED_ADDR_CTRL, PR_TAGGED_ADDR_ENABLE, 0, 0, 0) ==
- (uptr)-1 ||
- !internal_prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0)) {
+ if ((internal_iserror(internal_prctl(PR_SET_TAGGED_ADDR_CTRL,
+ PR_TAGGED_ADDR_ENABLE, 0, 0, 0)) ||
+ !internal_prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0)) &&
+ flags()->fail_without_syscall_abi) {
Printf(
"FATAL: HWAddressSanitizer failed to enable tagged address syscall "
"ABI.\nSuggest check `sysctl abi.tagged_addr_disabled` "
@@ -174,6 +181,18 @@ bool InitShadow() {
// High memory starts where allocated shadow allows.
kHighMemStart = ShadowToMem(kHighShadowStart);
+#if defined(__x86_64__)
+ constexpr uptr kAliasRegionOffset = 1ULL << (kTaggableRegionCheckShift - 1);
+ kAliasRegionStart =
+ __hwasan_shadow_memory_dynamic_address + kAliasRegionOffset;
+
+ CHECK_EQ(kAliasRegionStart >> kTaggableRegionCheckShift,
+ __hwasan_shadow_memory_dynamic_address >> kTaggableRegionCheckShift);
+ CHECK_EQ(
+ (kAliasRegionStart + kAliasRegionOffset - 1) >> kTaggableRegionCheckShift,
+ __hwasan_shadow_memory_dynamic_address >> kTaggableRegionCheckShift);
+#endif
+
// Check the sanity of the defined memory ranges (there might be gaps).
CHECK_EQ(kHighMemStart % GetMmapGranularity(), 0);
CHECK_GT(kHighMemStart, kHighShadowEnd);
@@ -217,7 +236,9 @@ void InitThreads() {
}
bool MemIsApp(uptr p) {
+#if !defined(__x86_64__) // Memory outside the alias range has non-zero tags.
CHECK(GetTagFromPointer(p) == 0);
+#endif
return p >= kHighMemStart || (p >= kLowMemStart && p <= kLowMemEnd);
}
diff --git a/libsanitizer/hwasan/hwasan_mapping.h b/libsanitizer/hwasan/hwasan_mapping.h
index c149687bdfa..8243d1ec7ed 100644
--- a/libsanitizer/hwasan/hwasan_mapping.h
+++ b/libsanitizer/hwasan/hwasan_mapping.h
@@ -48,6 +48,8 @@ extern uptr kHighShadowEnd;
extern uptr kHighMemStart;
extern uptr kHighMemEnd;
+extern uptr kAliasRegionStart;
+
inline uptr MemToShadow(uptr untagged_addr) {
return (untagged_addr >> kShadowScale) +
__hwasan_shadow_memory_dynamic_address;
diff --git a/libsanitizer/hwasan/hwasan_memintrinsics.cpp b/libsanitizer/hwasan/hwasan_memintrinsics.cpp
index e82d77a1bc1..fab017aae60 100644
--- a/libsanitizer/hwasan/hwasan_memintrinsics.cpp
+++ b/libsanitizer/hwasan/hwasan_memintrinsics.cpp
@@ -24,7 +24,7 @@ using namespace __hwasan;
void *__hwasan_memset(void *block, int c, uptr size) {
CheckAddressSized<ErrorAction::Recover, AccessType::Store>(
reinterpret_cast<uptr>(block), size);
- return memset(UntagPtr(block), c, size);
+ return memset(block, c, size);
}
void *__hwasan_memcpy(void *to, const void *from, uptr size) {
@@ -32,7 +32,7 @@ void *__hwasan_memcpy(void *to, const void *from, uptr size) {
reinterpret_cast<uptr>(to), size);
CheckAddressSized<ErrorAction::Recover, AccessType::Load>(
reinterpret_cast<uptr>(from), size);
- return memcpy(UntagPtr(to), UntagPtr(from), size);
+ return memcpy(to, from, size);
}
void *__hwasan_memmove(void *to, const void *from, uptr size) {
diff --git a/libsanitizer/hwasan/hwasan_new_delete.cpp b/libsanitizer/hwasan/hwasan_new_delete.cpp
index 8d01d3944f2..69cddda736e 100644
--- a/libsanitizer/hwasan/hwasan_new_delete.cpp
+++ b/libsanitizer/hwasan/hwasan_new_delete.cpp
@@ -27,6 +27,12 @@
void *res = hwasan_malloc(size, &stack);\
if (!nothrow && UNLIKELY(!res)) ReportOutOfMemory(size, &stack);\
return res
+#define OPERATOR_NEW_ALIGN_BODY(nothrow) \
+ GET_MALLOC_STACK_TRACE; \
+ void *res = hwasan_aligned_alloc(static_cast<uptr>(align), size, &stack); \
+ if (!nothrow && UNLIKELY(!res)) \
+ ReportOutOfMemory(size, &stack); \
+ return res
#define OPERATOR_DELETE_BODY \
GET_MALLOC_STACK_TRACE; \
@@ -50,6 +56,7 @@ using namespace __hwasan;
// Fake std::nothrow_t to avoid including <new>.
namespace std {
struct nothrow_t {};
+ enum class align_val_t : size_t {};
} // namespace std
@@ -66,6 +73,22 @@ INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
void *operator new[](size_t size, std::nothrow_t const&) {
OPERATOR_NEW_BODY(true /*nothrow*/);
}
+INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void *operator new(
+ size_t size, std::align_val_t align) {
+ OPERATOR_NEW_ALIGN_BODY(false /*nothrow*/);
+}
+INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void *operator new[](
+ size_t size, std::align_val_t align) {
+ OPERATOR_NEW_ALIGN_BODY(false /*nothrow*/);
+}
+INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void *operator new(
+ size_t size, std::align_val_t align, std::nothrow_t const &) {
+ OPERATOR_NEW_ALIGN_BODY(true /*nothrow*/);
+}
+INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void *operator new[](
+ size_t size, std::align_val_t align, std::nothrow_t const &) {
+ OPERATOR_NEW_ALIGN_BODY(true /*nothrow*/);
+}
INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
void operator delete(void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY; }
@@ -77,5 +100,21 @@ INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
void operator delete[](void *ptr, std::nothrow_t const&) {
OPERATOR_DELETE_BODY;
}
+INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void operator delete(
+ void *ptr, std::align_val_t align) NOEXCEPT {
+ OPERATOR_DELETE_BODY;
+}
+INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void operator delete[](
+ void *ptr, std::align_val_t) NOEXCEPT {
+ OPERATOR_DELETE_BODY;
+}
+INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void operator delete(
+ void *ptr, std::align_val_t, std::nothrow_t const &) NOEXCEPT {
+ OPERATOR_DELETE_BODY;
+}
+INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void operator delete[](
+ void *ptr, std::align_val_t, std::nothrow_t const &) NOEXCEPT {
+ OPERATOR_DELETE_BODY;
+}
#endif // OPERATOR_NEW_BODY
diff --git a/libsanitizer/hwasan/hwasan_report.cpp b/libsanitizer/hwasan/hwasan_report.cpp
index 894a149775f..c0217799391 100644
--- a/libsanitizer/hwasan/hwasan_report.cpp
+++ b/libsanitizer/hwasan/hwasan_report.cpp
@@ -43,12 +43,16 @@ class ScopedReport {
}
~ScopedReport() {
+ void (*report_cb)(const char *);
{
BlockingMutexLock lock(&error_message_lock_);
- if (fatal)
- SetAbortMessage(error_message_.data());
+ report_cb = error_report_callback_;
error_message_ptr_ = nullptr;
}
+ if (report_cb)
+ report_cb(error_message_.data());
+ if (fatal)
+ SetAbortMessage(error_message_.data());
if (common_flags()->print_module_map >= 2 ||
(fatal && common_flags()->print_module_map))
DumpProcessMap();
@@ -66,6 +70,12 @@ class ScopedReport {
// overwrite old trailing '\0', keep new trailing '\0' untouched.
internal_memcpy(&(*error_message_ptr_)[old_size - 1], msg, len);
}
+
+ static void SetErrorReportCallback(void (*callback)(const char *)) {
+ BlockingMutexLock lock(&error_message_lock_);
+ error_report_callback_ = callback;
+ }
+
private:
ScopedErrorReportLock error_report_lock_;
InternalMmapVector<char> error_message_;
@@ -73,10 +83,12 @@ class ScopedReport {
static InternalMmapVector<char> *error_message_ptr_;
static BlockingMutex error_message_lock_;
+ static void (*error_report_callback_)(const char *);
};
InternalMmapVector<char> *ScopedReport::error_message_ptr_;
BlockingMutex ScopedReport::error_message_lock_;
+void (*ScopedReport::error_report_callback_)(const char *);
// If there is an active ScopedReport, append to its error message.
void AppendToErrorMessageBuffer(const char *buffer) {
@@ -212,7 +224,7 @@ static void PrintStackAllocations(StackAllocationsRingBuffer *sa,
// We didn't find any locals. Most likely we don't have symbols, so dump
// the information that we have for offline analysis.
- InternalScopedString frame_desc(GetPageSizeCached() * 2);
+ InternalScopedString frame_desc;
Printf("Previously allocated frames:\n");
for (uptr i = 0; i < frames; i++) {
const uptr *record_addr = &(*sa)[i];
@@ -447,7 +459,7 @@ static void PrintTagInfoAroundAddr(tag_t *tag_ptr, uptr num_rows,
RoundDownTo(reinterpret_cast<uptr>(tag_ptr), row_len));
tag_t *beg_row = center_row_beg - row_len * (num_rows / 2);
tag_t *end_row = center_row_beg + row_len * ((num_rows + 1) / 2);
- InternalScopedString s(GetPageSizeCached() * 8);
+ InternalScopedString s;
for (tag_t *row = beg_row; row < end_row; row += row_len) {
s.append("%s", row == center_row_beg ? "=>" : " ");
s.append("%p:", row);
@@ -535,7 +547,7 @@ void ReportTailOverwritten(StackTrace *stack, uptr tagged_addr, uptr orig_size,
GetStackTraceFromId(chunk.GetAllocStackId()).Print();
}
- InternalScopedString s(GetPageSizeCached() * 8);
+ InternalScopedString s;
CHECK_GT(tail_size, 0U);
CHECK_LT(tail_size, kShadowAlignment);
u8 *tail = reinterpret_cast<u8*>(untagged_addr + orig_size);
@@ -650,3 +662,7 @@ void ReportRegisters(uptr *frame, uptr pc) {
}
} // namespace __hwasan
+
+void __hwasan_set_error_report_callback(void (*callback)(const char *)) {
+ __hwasan::ScopedReport::SetErrorReportCallback(callback);
+}
diff --git a/libsanitizer/hwasan/hwasan_setjmp.S b/libsanitizer/hwasan/hwasan_setjmp.S
index 0c135433194..381af63363c 100644
--- a/libsanitizer/hwasan/hwasan_setjmp.S
+++ b/libsanitizer/hwasan/hwasan_setjmp.S
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_asm.h"
+#include "builtins/assembly.h"
#if HWASAN_WITH_INTERCEPTORS && defined(__aarch64__)
#include "sanitizer_common/sanitizer_platform.h"
@@ -34,6 +35,7 @@
ASM_TYPE_FUNCTION(__interceptor_setjmp)
__interceptor_setjmp:
CFI_STARTPROC
+ BTI_C
mov x1, #0
b __interceptor_sigsetjmp
CFI_ENDPROC
@@ -46,6 +48,7 @@ ASM_SIZE(__interceptor_setjmp)
ASM_TYPE_FUNCTION(__interceptor_setjmp_bionic)
__interceptor_setjmp_bionic:
CFI_STARTPROC
+ BTI_C
mov x1, #1
b __interceptor_sigsetjmp
CFI_ENDPROC
@@ -56,6 +59,7 @@ ASM_SIZE(__interceptor_setjmp_bionic)
ASM_TYPE_FUNCTION(__interceptor_sigsetjmp)
__interceptor_sigsetjmp:
CFI_STARTPROC
+ BTI_C
stp x19, x20, [x0, #0<<3]
stp x21, x22, [x0, #2<<3]
stp x23, x24, [x0, #4<<3]
@@ -98,3 +102,5 @@ ALIAS __interceptor_setjmp, _setjmp
// We do not need executable stack.
NO_EXEC_STACK_DIRECTIVE
+
+GNU_PROPERTY_BTI_PAC
diff --git a/libsanitizer/hwasan/hwasan_tag_mismatch_aarch64.S b/libsanitizer/hwasan/hwasan_tag_mismatch_aarch64.S
index 08df12736bb..bcb0df42019 100644
--- a/libsanitizer/hwasan/hwasan_tag_mismatch_aarch64.S
+++ b/libsanitizer/hwasan/hwasan_tag_mismatch_aarch64.S
@@ -1,4 +1,5 @@
#include "sanitizer_common/sanitizer_asm.h"
+#include "builtins/assembly.h"
// The content of this file is AArch64-only:
#if defined(__aarch64__)
@@ -74,6 +75,8 @@
.global __hwasan_tag_mismatch
.type __hwasan_tag_mismatch, %function
__hwasan_tag_mismatch:
+ BTI_J
+
// Compute the granule position one past the end of the access.
mov x16, #1
and x17, x1, #0xf
@@ -106,6 +109,7 @@ __hwasan_tag_mismatch:
.type __hwasan_tag_mismatch_v2, %function
__hwasan_tag_mismatch_v2:
CFI_STARTPROC
+ BTI_J
// Set the CFA to be the return address for caller of __hwasan_check_*. Note
// that we do not emit CFI predicates to describe the contents of this stack
@@ -150,3 +154,5 @@ __hwasan_tag_mismatch_v2:
// We do not need executable stack.
NO_EXEC_STACK_DIRECTIVE
+
+GNU_PROPERTY_BTI_PAC
diff --git a/libsanitizer/hwasan/hwasan_thread.cpp b/libsanitizer/hwasan/hwasan_thread.cpp
index b81a6350c05..bb4d56abed0 100644
--- a/libsanitizer/hwasan/hwasan_thread.cpp
+++ b/libsanitizer/hwasan/hwasan_thread.cpp
@@ -35,6 +35,10 @@ void Thread::InitRandomState() {
}
void Thread::Init(uptr stack_buffer_start, uptr stack_buffer_size) {
+ CHECK_EQ(0, unique_id_); // try to catch bad stack reuse
+ CHECK_EQ(0, stack_top_);
+ CHECK_EQ(0, stack_bottom_);
+
static u64 unique_id;
unique_id_ = unique_id++;
if (auto sz = flags()->heap_history_size)
@@ -113,18 +117,21 @@ static u32 xorshift(u32 state) {
}
// Generate a (pseudo-)random non-zero tag.
-tag_t Thread::GenerateRandomTag() {
+tag_t Thread::GenerateRandomTag(uptr num_bits) {
+ DCHECK_GT(num_bits, 0);
if (tagging_disabled_) return 0;
tag_t tag;
+ const uptr tag_mask = (1ULL << num_bits) - 1;
do {
if (flags()->random_tags) {
if (!random_buffer_)
random_buffer_ = random_state_ = xorshift(random_state_);
CHECK(random_buffer_);
- tag = random_buffer_ & 0xFF;
- random_buffer_ >>= 8;
+ tag = random_buffer_ & tag_mask;
+ random_buffer_ >>= num_bits;
} else {
- tag = random_state_ = (random_state_ + 1) & 0xFF;
+ random_state_ += 1;
+ tag = random_state_ & tag_mask;
}
} while (!tag);
return tag;
diff --git a/libsanitizer/hwasan/hwasan_thread.h b/libsanitizer/hwasan/hwasan_thread.h
index ebcdb791fb3..1c71cab41c4 100644
--- a/libsanitizer/hwasan/hwasan_thread.h
+++ b/libsanitizer/hwasan/hwasan_thread.h
@@ -42,7 +42,7 @@ class Thread {
HeapAllocationsRingBuffer *heap_allocations() { return heap_allocations_; }
StackAllocationsRingBuffer *stack_allocations() { return stack_allocations_; }
- tag_t GenerateRandomTag();
+ tag_t GenerateRandomTag(uptr num_bits = kTagBits);
void DisableTagging() { tagging_disabled_++; }
void EnableTagging() { tagging_disabled_--; }
@@ -74,8 +74,6 @@ class Thread {
HeapAllocationsRingBuffer *heap_allocations_;
StackAllocationsRingBuffer *stack_allocations_;
- Thread *next_; // All live threads form a linked list.
-
u64 unique_id_; // counting from zero.
u32 tagging_disabled_; // if non-zero, malloc uses zero tag in this thread.
diff --git a/libsanitizer/hwasan/hwasan_thread_list.h b/libsanitizer/hwasan/hwasan_thread_list.h
index 914b632d977..11c586314ce 100644
--- a/libsanitizer/hwasan/hwasan_thread_list.h
+++ b/libsanitizer/hwasan/hwasan_thread_list.h
@@ -66,40 +66,6 @@ static uptr RingBufferSize() {
return 0;
}
-struct ThreadListHead {
- Thread *list_;
-
- ThreadListHead() : list_(nullptr) {}
-
- void Push(Thread *t) {
- t->next_ = list_;
- list_ = t;
- }
-
- Thread *Pop() {
- Thread *t = list_;
- if (t)
- list_ = t->next_;
- return t;
- }
-
- void Remove(Thread *t) {
- Thread **cur = &list_;
- while (*cur != t) cur = &(*cur)->next_;
- CHECK(*cur && "thread not found");
- *cur = (*cur)->next_;
- }
-
- template <class CB>
- void ForEach(CB cb) {
- Thread *t = list_;
- while (t) {
- cb(t);
- t = t->next_;
- }
- }
-};
-
struct ThreadStats {
uptr n_live_threads;
uptr total_stack_size;
@@ -120,17 +86,23 @@ class HwasanThreadList {
}
Thread *CreateCurrentThread() {
- Thread *t;
+ Thread *t = nullptr;
{
- SpinMutexLock l(&list_mutex_);
- t = free_list_.Pop();
- if (t) {
- uptr start = (uptr)t - ring_buffer_size_;
- internal_memset((void *)start, 0, ring_buffer_size_ + sizeof(Thread));
- } else {
- t = AllocThread();
+ SpinMutexLock l(&free_list_mutex_);
+ if (!free_list_.empty()) {
+ t = free_list_.back();
+ free_list_.pop_back();
}
- live_list_.Push(t);
+ }
+ if (t) {
+ uptr start = (uptr)t - ring_buffer_size_;
+ internal_memset((void *)start, 0, ring_buffer_size_ + sizeof(Thread));
+ } else {
+ t = AllocThread();
+ }
+ {
+ SpinMutexLock l(&live_list_mutex_);
+ live_list_.push_back(t);
}
t->Init((uptr)t - ring_buffer_size_, ring_buffer_size_);
AddThreadStats(t);
@@ -142,13 +114,26 @@ class HwasanThreadList {
ReleaseMemoryPagesToOS(start, start + thread_alloc_size_);
}
+ void RemoveThreadFromLiveList(Thread *t) {
+ SpinMutexLock l(&live_list_mutex_);
+ for (Thread *&t2 : live_list_)
+ if (t2 == t) {
+ // To remove t2, copy the last element of the list in t2's position, and
+ // pop_back(). This works even if t2 is itself the last element.
+ t2 = live_list_.back();
+ live_list_.pop_back();
+ return;
+ }
+ CHECK(0 && "thread not found in live list");
+ }
+
void ReleaseThread(Thread *t) {
RemoveThreadStats(t);
t->Destroy();
- SpinMutexLock l(&list_mutex_);
- live_list_.Remove(t);
- free_list_.Push(t);
DontNeedThread(t);
+ RemoveThreadFromLiveList(t);
+ SpinMutexLock l(&free_list_mutex_);
+ free_list_.push_back(t);
}
Thread *GetThreadByBufferAddress(uptr p) {
@@ -165,8 +150,8 @@ class HwasanThreadList {
template <class CB>
void VisitAllLiveThreads(CB cb) {
- SpinMutexLock l(&list_mutex_);
- live_list_.ForEach(cb);
+ SpinMutexLock l(&live_list_mutex_);
+ for (Thread *t : live_list_) cb(t);
}
void AddThreadStats(Thread *t) {
@@ -188,6 +173,7 @@ class HwasanThreadList {
private:
Thread *AllocThread() {
+ SpinMutexLock l(&free_space_mutex_);
uptr align = ring_buffer_size_ * 2;
CHECK(IsAligned(free_space_, align));
Thread *t = (Thread *)(free_space_ + ring_buffer_size_);
@@ -196,14 +182,16 @@ class HwasanThreadList {
return t;
}
+ SpinMutex free_space_mutex_;
uptr free_space_;
uptr free_space_end_;
uptr ring_buffer_size_;
uptr thread_alloc_size_;
- ThreadListHead free_list_;
- ThreadListHead live_list_;
- SpinMutex list_mutex_;
+ SpinMutex free_list_mutex_;
+ InternalMmapVector<Thread *> free_list_;
+ SpinMutex live_list_mutex_;
+ InternalMmapVector<Thread *> live_list_;
ThreadStats stats_;
SpinMutex stats_mutex_;
diff --git a/libsanitizer/include/sanitizer/common_interface_defs.h b/libsanitizer/include/sanitizer/common_interface_defs.h
index b4f977bf557..cd69285b8d4 100644
--- a/libsanitizer/include/sanitizer/common_interface_defs.h
+++ b/libsanitizer/include/sanitizer/common_interface_defs.h
@@ -43,6 +43,9 @@ void __sanitizer_set_report_path(const char *path);
// Tell the tools to write their reports to the provided file descriptor
// (casted to void *).
void __sanitizer_set_report_fd(void *fd);
+// Get the current full report file path, if a path was specified by
+// an earlier call to __sanitizer_set_report_path. Returns null otherwise.
+const char *__sanitizer_get_report_path();
// 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
diff --git a/libsanitizer/include/sanitizer/dfsan_interface.h b/libsanitizer/include/sanitizer/dfsan_interface.h
index 18b2c81a602..40f9379b557 100644
--- a/libsanitizer/include/sanitizer/dfsan_interface.h
+++ b/libsanitizer/include/sanitizer/dfsan_interface.h
@@ -22,6 +22,7 @@ extern "C" {
#endif
typedef uint16_t dfsan_label;
+typedef uint32_t dfsan_origin;
/// Stores information associated with a specific label identifier. A label
/// may be a base label created using dfsan_create_label, with associated
@@ -63,6 +64,12 @@ void dfsan_add_label(dfsan_label label, void *addr, size_t size);
/// value.
dfsan_label dfsan_get_label(long data);
+/// Retrieves the immediate origin associated with the given data. The returned
+/// origin may point to another origin.
+///
+/// The type of 'data' is arbitrary.
+dfsan_origin dfsan_get_origin(long data);
+
/// Retrieves the label associated with the data at the given address.
dfsan_label dfsan_read_label(const void *addr, size_t size);
@@ -110,6 +117,15 @@ void dfsan_weak_hook_memcmp(void *caller_pc, const void *s1, const void *s2,
void dfsan_weak_hook_strncmp(void *caller_pc, const char *s1, const char *s2,
size_t n, dfsan_label s1_label,
dfsan_label s2_label, dfsan_label n_label);
+
+/// Prints the origin trace of the label at the address addr to stderr. It also
+/// prints description at the beginning of the trace. If origin tracking is not
+/// on, or the address is not labeled, it prints nothing.
+void dfsan_print_origin_trace(const void *addr, const char *description);
+
+/// Retrieves the very first origin associated with the data at the given
+/// address.
+dfsan_origin dfsan_get_init_origin(const void *addr);
#ifdef __cplusplus
} // extern "C"
diff --git a/libsanitizer/include/sanitizer/hwasan_interface.h b/libsanitizer/include/sanitizer/hwasan_interface.h
index 4c9ad13aa0c..14035c05c63 100644
--- a/libsanitizer/include/sanitizer/hwasan_interface.h
+++ b/libsanitizer/include/sanitizer/hwasan_interface.h
@@ -73,6 +73,9 @@ extern "C" {
* accessed through the pointer in x, or -1 if the whole range is good. */
intptr_t __hwasan_test_shadow(const volatile void *x, size_t size);
+ /* Sets the callback function to be called during HWASan error reporting. */
+ void __hwasan_set_error_report_callback(void (*callback)(const char *));
+
int __sanitizer_posix_memalign(void **memptr, size_t alignment, size_t size);
void * __sanitizer_memalign(size_t alignment, size_t size);
void * __sanitizer_aligned_alloc(size_t alignment, size_t size);
diff --git a/libsanitizer/include/sanitizer/memprof_interface.h b/libsanitizer/include/sanitizer/memprof_interface.h
index a7212605100..76031de4014 100644
--- a/libsanitizer/include/sanitizer/memprof_interface.h
+++ b/libsanitizer/include/sanitizer/memprof_interface.h
@@ -53,6 +53,11 @@ void __memprof_print_accumulated_stats(void);
/// \returns Default options string.
const char *__memprof_default_options(void);
+/// Prints the memory profile to the current profile file.
+///
+/// \returns 0 on success.
+int __memprof_profile_dump(void);
+
#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/libsanitizer/include/sanitizer/tsan_interface.h b/libsanitizer/include/sanitizer/tsan_interface.h
index 96b8ad58541..565aa391a9f 100644
--- a/libsanitizer/include/sanitizer/tsan_interface.h
+++ b/libsanitizer/include/sanitizer/tsan_interface.h
@@ -67,6 +67,12 @@ static const unsigned __tsan_mutex_recursive_lock = 1 << 6;
// the corresponding __tsan_mutex_post_lock annotation.
static const unsigned __tsan_mutex_recursive_unlock = 1 << 7;
+// Convenient composed constants.
+static const unsigned __tsan_mutex_try_read_lock =
+ __tsan_mutex_read_lock | __tsan_mutex_try_lock;
+static const unsigned __tsan_mutex_try_read_lock_failed =
+ __tsan_mutex_try_read_lock | __tsan_mutex_try_lock_failed;
+
// Annotate creation of a mutex.
// Supported flags: mutex creation flags.
void __tsan_mutex_create(void *addr, unsigned flags);
@@ -141,7 +147,7 @@ void __tsan_external_write(void *addr, void *caller_pc, void *tag);
// and freed by __tsan_destroy_fiber.
// - TSAN context of current fiber or thread can be obtained
// by calling __tsan_get_current_fiber.
-// - __tsan_switch_to_fiber should be called immediatly before switch
+// - __tsan_switch_to_fiber should be called immediately before switch
// to fiber, such as call of swapcontext.
// - Fiber name can be set by __tsan_set_fiber_name.
void *__tsan_get_current_fiber(void);
@@ -154,6 +160,15 @@ void __tsan_set_fiber_name(void *fiber, const char *name);
// Do not establish a happens-before relation between fibers
static const unsigned __tsan_switch_to_fiber_no_sync = 1 << 0;
+// User-provided callback invoked on TSan initialization.
+void __tsan_on_initialize();
+
+// User-provided callback invoked on TSan shutdown.
+// `failed` - Nonzero if TSan did detect issues, zero otherwise.
+// Return `0` if TSan should exit as if no issues were detected. Return nonzero
+// if TSan should exit as if issues were detected.
+int __tsan_on_finalize(int failed);
+
#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/libsanitizer/include/sanitizer/tsan_interface_atomic.h b/libsanitizer/include/sanitizer/tsan_interface_atomic.h
index 8052bc1d56b..5e41e2256c3 100644
--- a/libsanitizer/include/sanitizer/tsan_interface_atomic.h
+++ b/libsanitizer/include/sanitizer/tsan_interface_atomic.h
@@ -30,7 +30,7 @@ __extension__ typedef __int128 __tsan_atomic128;
#endif
// Part of ABI, do not change.
-// https://github.com/llvm/llvm-project/blob/master/libcxx/include/atomic
+// https://github.com/llvm/llvm-project/blob/main/libcxx/include/atomic
typedef enum {
__tsan_memory_order_relaxed,
__tsan_memory_order_consume,
diff --git a/libsanitizer/interception/interception_linux.cpp b/libsanitizer/interception/interception_linux.cpp
index 6883608d44f..5111a87f0a6 100644
--- a/libsanitizer/interception/interception_linux.cpp
+++ b/libsanitizer/interception/interception_linux.cpp
@@ -63,8 +63,8 @@ bool InterceptFunction(const char *name, uptr *ptr_to_real, uptr func,
return addr && (func == wrapper);
}
-// Android and Solaris do not have dlvsym
-#if !SANITIZER_ANDROID && !SANITIZER_SOLARIS
+// dlvsym is a GNU extension supported by some other platforms.
+#if SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD
static void *GetFuncAddr(const char *name, const char *ver) {
return dlvsym(RTLD_NEXT, name, ver);
}
@@ -75,7 +75,7 @@ bool InterceptFunction(const char *name, const char *ver, uptr *ptr_to_real,
*ptr_to_real = (uptr)addr;
return addr && (func == wrapper);
}
-#endif // !SANITIZER_ANDROID
+#endif // SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD
} // namespace __interception
diff --git a/libsanitizer/interception/interception_linux.h b/libsanitizer/interception/interception_linux.h
index 097375fd1c1..a08f8cb98c4 100644
--- a/libsanitizer/interception/interception_linux.h
+++ b/libsanitizer/interception/interception_linux.h
@@ -35,8 +35,8 @@ bool InterceptFunction(const char *name, const char *ver, uptr *ptr_to_real,
(::__interception::uptr) & (func), \
(::__interception::uptr) & WRAP(func))
-// Android and Solaris do not have dlvsym
-#if !SANITIZER_ANDROID && !SANITIZER_SOLARIS
+// dlvsym is a GNU extension supported by some other platforms.
+#if SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD
#define INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver) \
::__interception::InterceptFunction( \
#func, symver, \
@@ -46,7 +46,7 @@ bool InterceptFunction(const char *name, const char *ver, uptr *ptr_to_real,
#else
#define INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver) \
INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func)
-#endif // !SANITIZER_ANDROID && !SANITIZER_SOLARIS
+#endif // SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD
#endif // INTERCEPTION_LINUX_H
#endif // SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD ||
diff --git a/libsanitizer/interception/interception_win.cpp b/libsanitizer/interception/interception_win.cpp
index 1a1c327e612..98bc756ae53 100644
--- a/libsanitizer/interception/interception_win.cpp
+++ b/libsanitizer/interception/interception_win.cpp
@@ -136,7 +136,7 @@ namespace __interception {
static const int kAddressLength = FIRST_32_SECOND_64(4, 8);
static const int kJumpInstructionLength = 5;
static const int kShortJumpInstructionLength = 2;
-static const int kIndirectJumpInstructionLength = 6;
+UNUSED static const int kIndirectJumpInstructionLength = 6;
static const int kBranchLength =
FIRST_32_SECOND_64(kJumpInstructionLength, kIndirectJumpInstructionLength);
static const int kDirectBranchLength = kBranchLength + kAddressLength;
@@ -165,7 +165,7 @@ static uptr GetMmapGranularity() {
return si.dwAllocationGranularity;
}
-static uptr RoundUpTo(uptr size, uptr boundary) {
+UNUSED static uptr RoundUpTo(uptr size, uptr boundary) {
return (size + boundary - 1) & ~(boundary - 1);
}
@@ -309,7 +309,7 @@ struct TrampolineMemoryRegion {
uptr max_size;
};
-static const uptr kTrampolineScanLimitRange = 1 << 31; // 2 gig
+UNUSED static const uptr kTrampolineScanLimitRange = 1 << 31; // 2 gig
static const int kMaxTrampolineRegion = 1024;
static TrampolineMemoryRegion TrampolineRegions[kMaxTrampolineRegion];
diff --git a/libsanitizer/lsan/lsan_allocator.cpp b/libsanitizer/lsan/lsan_allocator.cpp
index d86c3921395..91e34ebb321 100644
--- a/libsanitizer/lsan/lsan_allocator.cpp
+++ b/libsanitizer/lsan/lsan_allocator.cpp
@@ -123,14 +123,18 @@ void Deallocate(void *p) {
void *Reallocate(const StackTrace &stack, void *p, uptr new_size,
uptr alignment) {
- RegisterDeallocation(p);
if (new_size > max_malloc_size) {
- allocator.Deallocate(GetAllocatorCache(), p);
- return ReportAllocationSizeTooBig(new_size, stack);
+ ReportAllocationSizeTooBig(new_size, stack);
+ return nullptr;
}
- p = allocator.Reallocate(GetAllocatorCache(), p, new_size, alignment);
- RegisterAllocation(stack, p, new_size);
- return p;
+ RegisterDeallocation(p);
+ void *new_p =
+ allocator.Reallocate(GetAllocatorCache(), p, new_size, alignment);
+ if (new_p)
+ RegisterAllocation(stack, new_p, new_size);
+ else if (new_size != 0)
+ RegisterAllocation(stack, p, new_size);
+ return new_p;
}
void GetAllocatorCacheRange(uptr *begin, uptr *end) {
@@ -309,6 +313,16 @@ IgnoreObjectResult IgnoreObjectLocked(const void *p) {
return kIgnoreObjectInvalid;
}
}
+
+void GetAdditionalThreadContextPtrs(ThreadContextBase *tctx, void *ptrs) {
+ // This function can be used to treat memory reachable from `tctx` as live.
+ // This is useful for threads that have been created but not yet started.
+
+ // This is currently a no-op because the LSan `pthread_create()` interceptor
+ // blocks until the child thread starts which keeps the thread's `arg` pointer
+ // live.
+}
+
} // namespace __lsan
using namespace __lsan;
diff --git a/libsanitizer/lsan/lsan_allocator.h b/libsanitizer/lsan/lsan_allocator.h
index 17e13cd014b..9d763789154 100644
--- a/libsanitizer/lsan/lsan_allocator.h
+++ b/libsanitizer/lsan/lsan_allocator.h
@@ -50,7 +50,7 @@ struct ChunkMetadata {
};
#if defined(__mips64) || defined(__aarch64__) || defined(__i386__) || \
- defined(__arm__)
+ defined(__arm__) || SANITIZER_RISCV64
template <typename AddressSpaceViewTy>
struct AP32 {
static const uptr kSpaceBeg = 0;
diff --git a/libsanitizer/lsan/lsan_common.cpp b/libsanitizer/lsan/lsan_common.cpp
index 9e23aa9997a..74400d2e842 100644
--- a/libsanitizer/lsan/lsan_common.cpp
+++ b/libsanitizer/lsan/lsan_common.cpp
@@ -65,8 +65,34 @@ void RegisterLsanFlags(FlagParser *parser, Flags *f) {
if (flags()->log_threads) Report(__VA_ARGS__); \
} while (0)
-ALIGNED(64) static char suppression_placeholder[sizeof(SuppressionContext)];
-static SuppressionContext *suppression_ctx = nullptr;
+class LeakSuppressionContext {
+ bool parsed = false;
+ SuppressionContext context;
+ bool suppressed_stacks_sorted = true;
+ InternalMmapVector<u32> suppressed_stacks;
+
+ Suppression *GetSuppressionForAddr(uptr addr);
+ void LazyInit();
+
+ public:
+ LeakSuppressionContext(const char *supprression_types[],
+ int suppression_types_num)
+ : context(supprression_types, suppression_types_num) {}
+
+ Suppression *GetSuppressionForStack(u32 stack_trace_id);
+
+ const InternalMmapVector<u32> &GetSortedSuppressedStacks() {
+ if (!suppressed_stacks_sorted) {
+ suppressed_stacks_sorted = true;
+ SortAndDedup(suppressed_stacks);
+ }
+ return suppressed_stacks;
+ }
+ void PrintMatchedSuppressions();
+};
+
+ALIGNED(64) static char suppression_placeholder[sizeof(LeakSuppressionContext)];
+static LeakSuppressionContext *suppression_ctx = nullptr;
static const char kSuppressionLeak[] = "leak";
static const char *kSuppressionTypes[] = { kSuppressionLeak };
static const char kStdSuppressions[] =
@@ -86,14 +112,20 @@ static const char kStdSuppressions[] =
void InitializeSuppressions() {
CHECK_EQ(nullptr, suppression_ctx);
suppression_ctx = new (suppression_placeholder)
- SuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes));
- suppression_ctx->ParseFromFile(flags()->suppressions);
- if (&__lsan_default_suppressions)
- suppression_ctx->Parse(__lsan_default_suppressions());
- suppression_ctx->Parse(kStdSuppressions);
+ LeakSuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes));
+}
+
+void LeakSuppressionContext::LazyInit() {
+ if (!parsed) {
+ parsed = true;
+ context.ParseFromFile(flags()->suppressions);
+ if (&__lsan_default_suppressions)
+ context.Parse(__lsan_default_suppressions());
+ context.Parse(kStdSuppressions);
+ }
}
-static SuppressionContext *GetSuppressionContext() {
+static LeakSuppressionContext *GetSuppressionContext() {
CHECK(suppression_ctx);
return suppression_ctx;
}
@@ -221,6 +253,27 @@ extern "C" SANITIZER_WEAK_ATTRIBUTE void __libc_iterate_dynamic_tls(
pid_t, void (*cb)(void *, void *, uptr, void *), void *);
#endif
+static void ProcessThreadRegistry(Frontier *frontier) {
+ InternalMmapVector<uptr> ptrs;
+ GetThreadRegistryLocked()->RunCallbackForEachThreadLocked(
+ GetAdditionalThreadContextPtrs, &ptrs);
+
+ for (uptr i = 0; i < ptrs.size(); ++i) {
+ void *ptr = reinterpret_cast<void *>(ptrs[i]);
+ uptr chunk = PointsIntoChunk(ptr);
+ if (!chunk)
+ continue;
+ LsanMetadata m(chunk);
+ if (!m.allocated())
+ continue;
+
+ // Mark as reachable and add to frontier.
+ LOG_POINTERS("Treating pointer %p from ThreadContext as reachable\n", ptr);
+ m.set_tag(kReachable);
+ frontier->push_back(chunk);
+ }
+}
+
// Scans thread data (stacks and TLS) for heap pointers.
static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
Frontier *frontier) {
@@ -315,15 +368,15 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
__libc_iterate_dynamic_tls(os_id, cb, frontier);
#else
if (dtls && !DTLSInDestruction(dtls)) {
- for (uptr j = 0; j < dtls->dtv_size; ++j) {
- uptr dtls_beg = dtls->dtv[j].beg;
- uptr dtls_end = dtls_beg + dtls->dtv[j].size;
+ ForEachDVT(dtls, [&](const DTLS::DTV &dtv, int id) {
+ uptr dtls_beg = dtv.beg;
+ uptr dtls_end = dtls_beg + dtv.size;
if (dtls_beg < dtls_end) {
- LOG_THREADS("DTLS %zu at %p-%p.\n", j, dtls_beg, dtls_end);
+ LOG_THREADS("DTLS %zu at %p-%p.\n", id, dtls_beg, dtls_end);
ScanRangeForPointers(dtls_beg, dtls_end, frontier, "DTLS",
kReachable);
}
- }
+ });
} else {
// We are handling a thread with DTLS under destruction. Log about
// this and continue.
@@ -332,6 +385,9 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
#endif
}
}
+
+ // Add pointers reachable from ThreadContexts
+ ProcessThreadRegistry(frontier);
}
#endif // SANITIZER_FUCHSIA
@@ -390,6 +446,24 @@ static void MarkIndirectlyLeakedCb(uptr chunk, void *arg) {
}
}
+static void IgnoredSuppressedCb(uptr chunk, void *arg) {
+ CHECK(arg);
+ chunk = GetUserBegin(chunk);
+ LsanMetadata m(chunk);
+ if (!m.allocated() || m.tag() == kIgnored)
+ return;
+
+ const InternalMmapVector<u32> &suppressed =
+ *static_cast<const InternalMmapVector<u32> *>(arg);
+ uptr idx = InternalLowerBound(suppressed, m.stack_trace_id());
+ if (idx >= suppressed.size() || m.stack_trace_id() != suppressed[idx])
+ return;
+
+ LOG_POINTERS("Suppressed: chunk %p-%p of size %zu.\n", chunk,
+ chunk + m.requested_size(), m.requested_size());
+ m.set_tag(kIgnored);
+}
+
// ForEachChunk callback. If chunk is marked as ignored, adds its address to
// frontier.
static void CollectIgnoredCb(uptr chunk, void *arg) {
@@ -473,6 +547,12 @@ void ProcessPC(Frontier *frontier) {
// Sets the appropriate tag on each chunk.
static void ClassifyAllChunks(SuspendedThreadsList const &suspended_threads,
Frontier *frontier) {
+ const InternalMmapVector<u32> &suppressed_stacks =
+ GetSuppressionContext()->GetSortedSuppressedStacks();
+ if (!suppressed_stacks.empty()) {
+ ForEachChunk(IgnoredSuppressedCb,
+ const_cast<InternalMmapVector<u32> *>(&suppressed_stacks));
+ }
ForEachChunk(CollectIgnoredCb, frontier);
ProcessGlobalRegions(frontier);
ProcessThreads(suspended_threads, frontier);
@@ -532,18 +612,20 @@ static void CollectLeaksCb(uptr chunk, void *arg) {
}
}
-static void PrintMatchedSuppressions() {
+void LeakSuppressionContext::PrintMatchedSuppressions() {
InternalMmapVector<Suppression *> matched;
- GetSuppressionContext()->GetMatched(&matched);
+ context.GetMatched(&matched);
if (!matched.size())
return;
const char *line = "-----------------------------------------------------";
Printf("%s\n", line);
Printf("Suppressions used:\n");
Printf(" count bytes template\n");
- for (uptr i = 0; i < matched.size(); i++)
- Printf("%7zu %10zu %s\n", static_cast<uptr>(atomic_load_relaxed(
- &matched[i]->hit_count)), matched[i]->weight, matched[i]->templ);
+ for (uptr i = 0; i < matched.size(); i++) {
+ Printf("%7zu %10zu %s\n",
+ static_cast<uptr>(atomic_load_relaxed(&matched[i]->hit_count)),
+ matched[i]->weight, matched[i]->templ);
+ }
Printf("%s\n\n", line);
}
@@ -551,8 +633,7 @@ static void ReportIfNotSuspended(ThreadContextBase *tctx, void *arg) {
const InternalMmapVector<tid_t> &suspended_threads =
*(const InternalMmapVector<tid_t> *)arg;
if (tctx->status == ThreadStatusRunning) {
- uptr i = InternalLowerBound(suspended_threads, 0, suspended_threads.size(),
- tctx->os_id, CompareLess<int>());
+ uptr i = InternalLowerBound(suspended_threads, tctx->os_id);
if (i >= suspended_threads.size() || suspended_threads[i] != tctx->os_id)
Report("Running thread %d was not suspended. False leaks are possible.\n",
tctx->os_id);
@@ -595,43 +676,68 @@ static void CheckForLeaksCallback(const SuspendedThreadsList &suspended_threads,
param->success = true;
}
-static bool CheckForLeaks() {
- if (&__lsan_is_turned_off && __lsan_is_turned_off())
- return false;
- EnsureMainThreadIDIsCorrect();
- CheckForLeaksParam param;
- LockStuffAndStopTheWorld(CheckForLeaksCallback, ¶m);
-
- if (!param.success) {
- Report("LeakSanitizer has encountered a fatal error.\n");
- Report(
- "HINT: For debugging, try setting environment variable "
- "LSAN_OPTIONS=verbosity=1:log_threads=1\n");
- Report(
- "HINT: LeakSanitizer does not work under ptrace (strace, gdb, etc)\n");
- Die();
- }
- param.leak_report.ApplySuppressions();
- uptr unsuppressed_count = param.leak_report.UnsuppressedLeakCount();
- if (unsuppressed_count > 0) {
+static bool PrintResults(LeakReport &report) {
+ uptr unsuppressed_count = report.UnsuppressedLeakCount();
+ if (unsuppressed_count) {
Decorator d;
- Printf("\n"
- "================================================================="
- "\n");
+ Printf(
+ "\n"
+ "================================================================="
+ "\n");
Printf("%s", d.Error());
Report("ERROR: LeakSanitizer: detected memory leaks\n");
Printf("%s", d.Default());
- param.leak_report.ReportTopLeaks(flags()->max_leaks);
+ report.ReportTopLeaks(flags()->max_leaks);
}
if (common_flags()->print_suppressions)
- PrintMatchedSuppressions();
+ GetSuppressionContext()->PrintMatchedSuppressions();
if (unsuppressed_count > 0) {
- param.leak_report.PrintSummary();
+ report.PrintSummary();
return true;
}
return false;
}
+static bool CheckForLeaks() {
+ if (&__lsan_is_turned_off && __lsan_is_turned_off())
+ return false;
+ // Inside LockStuffAndStopTheWorld we can't run symbolizer, so we can't match
+ // suppressions. However if a stack id was previously suppressed, it should be
+ // suppressed in future checks as well.
+ for (int i = 0;; ++i) {
+ EnsureMainThreadIDIsCorrect();
+ CheckForLeaksParam param;
+ LockStuffAndStopTheWorld(CheckForLeaksCallback, ¶m);
+ if (!param.success) {
+ Report("LeakSanitizer has encountered a fatal error.\n");
+ Report(
+ "HINT: For debugging, try setting environment variable "
+ "LSAN_OPTIONS=verbosity=1:log_threads=1\n");
+ Report(
+ "HINT: LeakSanitizer does not work under ptrace (strace, gdb, "
+ "etc)\n");
+ Die();
+ }
+ // No new suppressions stacks, so rerun will not help and we can report.
+ if (!param.leak_report.ApplySuppressions())
+ return PrintResults(param.leak_report);
+
+ // No indirect leaks to report, so we are done here.
+ if (!param.leak_report.IndirectUnsuppressedLeakCount())
+ return PrintResults(param.leak_report);
+
+ if (i >= 8) {
+ Report("WARNING: LeakSanitizer gave up on indirect leaks suppression.\n");
+ return PrintResults(param.leak_report);
+ }
+
+ // We found a new previously unseen suppressed call stack. Rerun to make
+ // sure it does not hold indirect leaks.
+ VReport(1, "Rerun with %zu suppressed stacks.",
+ GetSuppressionContext()->GetSortedSuppressedStacks().size());
+ }
+}
+
static bool has_reported_leaks = false;
bool HasReportedLeaks() { return has_reported_leaks; }
@@ -652,21 +758,20 @@ static int DoRecoverableLeakCheck() {
void DoRecoverableLeakCheckVoid() { DoRecoverableLeakCheck(); }
-static Suppression *GetSuppressionForAddr(uptr addr) {
+Suppression *LeakSuppressionContext::GetSuppressionForAddr(uptr addr) {
Suppression *s = nullptr;
// Suppress by module name.
- SuppressionContext *suppressions = GetSuppressionContext();
if (const char *module_name =
Symbolizer::GetOrInit()->GetModuleNameForPc(addr))
- if (suppressions->Match(module_name, kSuppressionLeak, &s))
+ if (context.Match(module_name, kSuppressionLeak, &s))
return s;
// Suppress by file or function name.
SymbolizedStack *frames = Symbolizer::GetOrInit()->SymbolizePC(addr);
for (SymbolizedStack *cur = frames; cur; cur = cur->next) {
- if (suppressions->Match(cur->info.function, kSuppressionLeak, &s) ||
- suppressions->Match(cur->info.file, kSuppressionLeak, &s)) {
+ if (context.Match(cur->info.function, kSuppressionLeak, &s) ||
+ context.Match(cur->info.file, kSuppressionLeak, &s)) {
break;
}
}
@@ -674,12 +779,18 @@ static Suppression *GetSuppressionForAddr(uptr addr) {
return s;
}
-static Suppression *GetSuppressionForStack(u32 stack_trace_id) {
+Suppression *LeakSuppressionContext::GetSuppressionForStack(
+ u32 stack_trace_id) {
+ LazyInit();
StackTrace stack = StackDepotGet(stack_trace_id);
for (uptr i = 0; i < stack.size; i++) {
Suppression *s = GetSuppressionForAddr(
StackTrace::GetPreviousInstructionPc(stack.trace[i]));
- if (s) return s;
+ if (s) {
+ suppressed_stacks_sorted = false;
+ suppressed_stacks.push_back(stack_trace_id);
+ return s;
+ }
}
return nullptr;
}
@@ -784,22 +895,27 @@ void LeakReport::PrintSummary() {
bytes += leaks_[i].total_size;
allocations += leaks_[i].hit_count;
}
- InternalScopedString summary(kMaxSummaryLength);
+ InternalScopedString summary;
summary.append("%zu byte(s) leaked in %zu allocation(s).", bytes,
allocations);
ReportErrorSummary(summary.data());
}
-void LeakReport::ApplySuppressions() {
+uptr LeakReport::ApplySuppressions() {
+ LeakSuppressionContext *suppressions = GetSuppressionContext();
+ uptr new_suppressions = false;
for (uptr i = 0; i < leaks_.size(); i++) {
- Suppression *s = GetSuppressionForStack(leaks_[i].stack_trace_id);
+ Suppression *s =
+ suppressions->GetSuppressionForStack(leaks_[i].stack_trace_id);
if (s) {
s->weight += leaks_[i].total_size;
atomic_store_relaxed(&s->hit_count, atomic_load_relaxed(&s->hit_count) +
leaks_[i].hit_count);
leaks_[i].is_suppressed = true;
+ ++new_suppressions;
}
}
+ return new_suppressions;
}
uptr LeakReport::UnsuppressedLeakCount() {
@@ -809,6 +925,14 @@ uptr LeakReport::UnsuppressedLeakCount() {
return result;
}
+uptr LeakReport::IndirectUnsuppressedLeakCount() {
+ uptr result = 0;
+ for (uptr i = 0; i < leaks_.size(); i++)
+ if (!leaks_[i].is_suppressed && !leaks_[i].is_directly_leaked)
+ result++;
+ return result;
+}
+
} // namespace __lsan
#else // CAN_SANITIZE_LEAKS
namespace __lsan {
diff --git a/libsanitizer/lsan/lsan_common.h b/libsanitizer/lsan/lsan_common.h
index 1fdce087b3a..fe855cf3754 100644
--- a/libsanitizer/lsan/lsan_common.h
+++ b/libsanitizer/lsan/lsan_common.h
@@ -41,6 +41,8 @@
#define CAN_SANITIZE_LEAKS 1
#elif defined(__arm__) && SANITIZER_LINUX
#define CAN_SANITIZE_LEAKS 1
+#elif SANITIZER_RISCV64 && SANITIZER_LINUX
+#define CAN_SANITIZE_LEAKS 1
#elif SANITIZER_NETBSD || SANITIZER_FUCHSIA
#define CAN_SANITIZE_LEAKS 1
#else
@@ -50,6 +52,7 @@
namespace __sanitizer {
class FlagParser;
class ThreadRegistry;
+class ThreadContextBase;
struct DTLS;
}
@@ -63,8 +66,6 @@ enum ChunkTag {
kIgnored = 3
};
-const u32 kInvalidTid = (u32) -1;
-
struct Flags {
#define LSAN_FLAG(Type, Name, DefaultValue, Description) Type Name;
#include "lsan_flags.inc"
@@ -103,8 +104,9 @@ class LeakReport {
ChunkTag tag);
void ReportTopLeaks(uptr max_leaks);
void PrintSummary();
- void ApplySuppressions();
+ uptr ApplySuppressions();
uptr UnsuppressedLeakCount();
+ uptr IndirectUnsuppressedLeakCount();
private:
void PrintReportForLeak(uptr index);
@@ -141,6 +143,7 @@ InternalMmapVector<RootRegion> const *GetRootRegions();
void ScanRootRegion(Frontier *frontier, RootRegion const ®ion,
uptr region_begin, uptr region_end, bool is_readable);
void ForEachExtraStackRangeCb(uptr begin, uptr end, void* arg);
+void GetAdditionalThreadContextPtrs(ThreadContextBase *tctx, void *ptrs);
// Run stoptheworld while holding any platform-specific locks, as well as the
// allocator and thread registry locks.
void LockStuffAndStopTheWorld(StopTheWorldCallback callback,
diff --git a/libsanitizer/lsan/lsan_common_fuchsia.cpp b/libsanitizer/lsan/lsan_common_fuchsia.cpp
index 3c62c9433d3..2d35fa5b1cf 100644
--- a/libsanitizer/lsan/lsan_common_fuchsia.cpp
+++ b/libsanitizer/lsan/lsan_common_fuchsia.cpp
@@ -107,9 +107,7 @@ void LockStuffAndStopTheWorld(StopTheWorldCallback callback,
auto params = static_cast<const Params *>(data);
uptr begin = reinterpret_cast<uptr>(chunk);
uptr end = begin + size;
- auto i = __sanitizer::InternalLowerBound(params->allocator_caches, 0,
- params->allocator_caches.size(),
- begin, CompareLess<uptr>());
+ auto i = __sanitizer::InternalLowerBound(params->allocator_caches, begin);
if (i < params->allocator_caches.size() &&
params->allocator_caches[i] >= begin &&
end - params->allocator_caches[i] <= sizeof(AllocatorCache)) {
diff --git a/libsanitizer/lsan/lsan_fuchsia.h b/libsanitizer/lsan/lsan_fuchsia.h
index 65d20ea2114..e730d8f25f2 100644
--- a/libsanitizer/lsan/lsan_fuchsia.h
+++ b/libsanitizer/lsan/lsan_fuchsia.h
@@ -23,7 +23,7 @@
namespace __lsan {
-class ThreadContext : public ThreadContextLsanBase {
+class ThreadContext final : public ThreadContextLsanBase {
public:
explicit ThreadContext(int tid);
void OnCreated(void *arg) override;
diff --git a/libsanitizer/lsan/lsan_interceptors.cpp b/libsanitizer/lsan/lsan_interceptors.cpp
index bf8d316770e..90a90a56c54 100644
--- a/libsanitizer/lsan/lsan_interceptors.cpp
+++ b/libsanitizer/lsan/lsan_interceptors.cpp
@@ -460,7 +460,7 @@ INTERCEPTOR(int, pthread_create, void *th, void *attr,
if (res == 0) {
int tid = ThreadCreate(GetCurrentThread(), *(uptr *)th,
IsStateDetached(detached));
- CHECK_NE(tid, 0);
+ CHECK_NE(tid, kMainTid);
atomic_store(&p.tid, tid, memory_order_release);
while (atomic_load(&p.tid, memory_order_acquire) != 0)
internal_sched_yield();
diff --git a/libsanitizer/lsan/lsan_posix.cpp b/libsanitizer/lsan/lsan_posix.cpp
index 8e05915dd1b..5d1c3f6260d 100644
--- a/libsanitizer/lsan/lsan_posix.cpp
+++ b/libsanitizer/lsan/lsan_posix.cpp
@@ -48,7 +48,7 @@ void ThreadStart(u32 tid, tid_t os_id, ThreadType thread_type) {
OnStartedArgs args;
uptr stack_size = 0;
uptr tls_size = 0;
- GetThreadStackAndTls(tid == 0, &args.stack_begin, &stack_size,
+ GetThreadStackAndTls(tid == kMainTid, &args.stack_begin, &stack_size,
&args.tls_begin, &tls_size);
args.stack_end = args.stack_begin + stack_size;
args.tls_end = args.tls_begin + tls_size;
@@ -75,8 +75,8 @@ bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end,
}
void InitializeMainThread() {
- u32 tid = ThreadCreate(0, 0, true);
- CHECK_EQ(tid, 0);
+ u32 tid = ThreadCreate(kMainTid, 0, true);
+ CHECK_EQ(tid, kMainTid);
ThreadStart(tid, GetTid());
}
diff --git a/libsanitizer/lsan/lsan_thread.cpp b/libsanitizer/lsan/lsan_thread.cpp
index 371a1f29dfe..8efb54a6fb7 100644
--- a/libsanitizer/lsan/lsan_thread.cpp
+++ b/libsanitizer/lsan/lsan_thread.cpp
@@ -94,7 +94,7 @@ void ThreadJoin(u32 tid) {
}
void EnsureMainThreadIDIsCorrect() {
- if (GetCurrentThread() == 0)
+ if (GetCurrentThread() == kMainTid)
CurrentThreadContext()->os_id = GetTid();
}
diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_combined.h b/libsanitizer/sanitizer_common/sanitizer_allocator_combined.h
index 33f89d6d499..eb836bc4787 100644
--- a/libsanitizer/sanitizer_common/sanitizer_allocator_combined.h
+++ b/libsanitizer/sanitizer_common/sanitizer_allocator_combined.h
@@ -35,9 +35,9 @@ class CombinedAllocator {
secondary_.InitLinkerInitialized();
}
- void Init(s32 release_to_os_interval_ms) {
+ void Init(s32 release_to_os_interval_ms, uptr heap_start = 0) {
stats_.Init();
- primary_.Init(release_to_os_interval_ms);
+ primary_.Init(release_to_os_interval_ms, heap_start);
secondary_.Init();
}
diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_primary32.h b/libsanitizer/sanitizer_common/sanitizer_allocator_primary32.h
index b90dabbf776..fb5394cd39c 100644
--- a/libsanitizer/sanitizer_common/sanitizer_allocator_primary32.h
+++ b/libsanitizer/sanitizer_common/sanitizer_allocator_primary32.h
@@ -119,7 +119,8 @@ class SizeClassAllocator32 {
typedef SizeClassAllocator32<Params> ThisT;
typedef SizeClassAllocator32LocalCache<ThisT> AllocatorCache;
- void Init(s32 release_to_os_interval_ms) {
+ void Init(s32 release_to_os_interval_ms, uptr heap_start = 0) {
+ CHECK(!heap_start);
possible_regions.Init();
internal_memset(size_class_info_array, 0, sizeof(size_class_info_array));
}
diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_primary64.h b/libsanitizer/sanitizer_common/sanitizer_allocator_primary64.h
index 0a18b0c58ef..db30e138154 100644
--- a/libsanitizer/sanitizer_common/sanitizer_allocator_primary64.h
+++ b/libsanitizer/sanitizer_common/sanitizer_allocator_primary64.h
@@ -19,7 +19,7 @@ template<class SizeClassAllocator> struct SizeClassAllocator64LocalCache;
// The template parameter Params is a class containing the actual parameters.
//
// Space: a portion of address space of kSpaceSize bytes starting at SpaceBeg.
-// If kSpaceBeg is ~0 then SpaceBeg is chosen dynamically my mmap.
+// If kSpaceBeg is ~0 then SpaceBeg is chosen dynamically by mmap.
// Otherwise SpaceBeg=kSpaceBeg (fixed address).
// kSpaceSize is a power of two.
// At the beginning the entire space is mprotect-ed, then small parts of it
@@ -69,25 +69,45 @@ class SizeClassAllocator64 {
return base + (static_cast<uptr>(ptr32) << kCompactPtrScale);
}
- void Init(s32 release_to_os_interval_ms) {
+ // If heap_start is nonzero, assumes kSpaceSize bytes are already mapped R/W
+ // at heap_start and places the heap there. This mode requires kSpaceBeg ==
+ // ~(uptr)0.
+ void Init(s32 release_to_os_interval_ms, uptr heap_start = 0) {
uptr TotalSpaceSize = kSpaceSize + AdditionalSize();
- if (kUsingConstantSpaceBeg) {
- CHECK(IsAligned(kSpaceBeg, SizeClassMap::kMaxSize));
- CHECK_EQ(kSpaceBeg, address_range.Init(TotalSpaceSize,
- PrimaryAllocatorName, kSpaceBeg));
+ PremappedHeap = heap_start != 0;
+ if (PremappedHeap) {
+ CHECK(!kUsingConstantSpaceBeg);
+ NonConstSpaceBeg = heap_start;
+ uptr RegionInfoSize = AdditionalSize();
+ RegionInfoSpace =
+ address_range.Init(RegionInfoSize, PrimaryAllocatorName);
+ CHECK_NE(RegionInfoSpace, ~(uptr)0);
+ CHECK_EQ(RegionInfoSpace,
+ address_range.MapOrDie(RegionInfoSpace, RegionInfoSize,
+ "SizeClassAllocator: region info"));
+ MapUnmapCallback().OnMap(RegionInfoSpace, RegionInfoSize);
} else {
- // Combined allocator expects that an 2^N allocation is always aligned to
- // 2^N. For this to work, the start of the space needs to be aligned as
- // high as the largest size class (which also needs to be a power of 2).
- NonConstSpaceBeg = address_range.InitAligned(
- TotalSpaceSize, SizeClassMap::kMaxSize, PrimaryAllocatorName);
- CHECK_NE(NonConstSpaceBeg, ~(uptr)0);
+ if (kUsingConstantSpaceBeg) {
+ CHECK(IsAligned(kSpaceBeg, SizeClassMap::kMaxSize));
+ CHECK_EQ(kSpaceBeg,
+ address_range.Init(TotalSpaceSize, PrimaryAllocatorName,
+ kSpaceBeg));
+ } else {
+ // Combined allocator expects that an 2^N allocation is always aligned
+ // to 2^N. For this to work, the start of the space needs to be aligned
+ // as high as the largest size class (which also needs to be a power of
+ // 2).
+ NonConstSpaceBeg = address_range.InitAligned(
+ TotalSpaceSize, SizeClassMap::kMaxSize, PrimaryAllocatorName);
+ CHECK_NE(NonConstSpaceBeg, ~(uptr)0);
+ }
+ RegionInfoSpace = SpaceEnd();
+ MapWithCallbackOrDie(RegionInfoSpace, AdditionalSize(),
+ "SizeClassAllocator: region info");
}
SetReleaseToOSIntervalMs(release_to_os_interval_ms);
- MapWithCallbackOrDie(SpaceEnd(), AdditionalSize(),
- "SizeClassAllocator: region info");
// Check that the RegionInfo array is aligned on the CacheLine size.
- DCHECK_EQ(SpaceEnd() % kCacheLineSize, 0);
+ DCHECK_EQ(RegionInfoSpace % kCacheLineSize, 0);
}
s32 ReleaseToOSIntervalMs() const {
@@ -144,6 +164,17 @@ class SizeClassAllocator64 {
CompactPtrT *free_array = GetFreeArray(region_beg);
BlockingMutexLock l(®ion->mutex);
+#if SANITIZER_WINDOWS
+ /* On Windows unmapping of memory during __sanitizer_purge_allocator is
+ explicit and immediate, so unmapped regions must be explicitly mapped back
+ in when they are accessed again. */
+ if (region->rtoi.last_released_bytes > 0) {
+ MmapFixedOrDie(region_beg, region->mapped_user,
+ "SizeClassAllocator: region data");
+ region->rtoi.n_freed_at_last_release = 0;
+ region->rtoi.last_released_bytes = 0;
+ }
+#endif
if (UNLIKELY(region->num_freed_chunks < n_chunks)) {
if (UNLIKELY(!PopulateFreeArray(stat, class_id, region,
n_chunks - region->num_freed_chunks)))
@@ -360,8 +391,7 @@ class SizeClassAllocator64 {
}
~PackedCounterArray() {
if (buffer) {
- memory_mapper->UnmapPackedCounterArrayBuffer(
- reinterpret_cast<uptr>(buffer), buffer_size);
+ memory_mapper->UnmapPackedCounterArrayBuffer(buffer, buffer_size);
}
}
@@ -586,6 +616,11 @@ class SizeClassAllocator64 {
atomic_sint32_t release_to_os_interval_ms_;
+ uptr RegionInfoSpace;
+
+ // True if the user has already mapped the entire heap R/W.
+ bool PremappedHeap;
+
struct Stats {
uptr n_allocated;
uptr n_freed;
@@ -615,7 +650,7 @@ class SizeClassAllocator64 {
RegionInfo *GetRegionInfo(uptr class_id) const {
DCHECK_LT(class_id, kNumClasses);
- RegionInfo *regions = reinterpret_cast<RegionInfo *>(SpaceEnd());
+ RegionInfo *regions = reinterpret_cast<RegionInfo *>(RegionInfoSpace);
return ®ions[class_id];
}
@@ -640,6 +675,9 @@ class SizeClassAllocator64 {
}
bool MapWithCallback(uptr beg, uptr size, const char *name) {
+ if (PremappedHeap)
+ return beg >= NonConstSpaceBeg &&
+ beg + size <= NonConstSpaceBeg + kSpaceSize;
uptr mapped = address_range.Map(beg, size, name);
if (UNLIKELY(!mapped))
return false;
@@ -649,11 +687,18 @@ class SizeClassAllocator64 {
}
void MapWithCallbackOrDie(uptr beg, uptr size, const char *name) {
+ if (PremappedHeap) {
+ CHECK_GE(beg, NonConstSpaceBeg);
+ CHECK_LE(beg + size, NonConstSpaceBeg + kSpaceSize);
+ return;
+ }
CHECK_EQ(beg, address_range.MapOrDie(beg, size, name));
MapUnmapCallback().OnMap(beg, size);
}
void UnmapWithCallbackOrDie(uptr beg, uptr size) {
+ if (PremappedHeap)
+ return;
MapUnmapCallback().OnUnmap(beg, size);
address_range.Unmap(beg, size);
}
@@ -792,17 +837,16 @@ class SizeClassAllocator64 {
return released_bytes;
}
- uptr MapPackedCounterArrayBuffer(uptr buffer_size) {
+ void *MapPackedCounterArrayBuffer(uptr buffer_size) {
// TODO(alekseyshl): The idea to explore is to check if we have enough
// space between num_freed_chunks*sizeof(CompactPtrT) and
// mapped_free_array to fit buffer_size bytes and use that space instead
// of mapping a temporary one.
- return reinterpret_cast<uptr>(
- MmapOrDieOnFatalError(buffer_size, "ReleaseToOSPageCounters"));
+ return MmapOrDieOnFatalError(buffer_size, "ReleaseToOSPageCounters");
}
- void UnmapPackedCounterArrayBuffer(uptr buffer, uptr buffer_size) {
- UnmapOrDie(reinterpret_cast<void *>(buffer), buffer_size);
+ void UnmapPackedCounterArrayBuffer(void *buffer, uptr buffer_size) {
+ UnmapOrDie(buffer, buffer_size);
}
// Releases [from, to) range of pages back to OS.
@@ -823,6 +867,9 @@ class SizeClassAllocator64 {
// Attempts to release RAM occupied by freed chunks back to OS. The region is
// expected to be locked.
+ //
+ // TODO(morehouse): Support a callback on memory release so HWASan can release
+ // aliases as well.
void MaybeReleaseToOS(uptr class_id, bool force) {
RegionInfo *region = GetRegionInfo(class_id);
const uptr chunk_size = ClassIdToSize(class_id);
diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_size_class_map.h b/libsanitizer/sanitizer_common/sanitizer_allocator_size_class_map.h
index 12d8c892307..c50d13303ed 100644
--- a/libsanitizer/sanitizer_common/sanitizer_allocator_size_class_map.h
+++ b/libsanitizer/sanitizer_common/sanitizer_allocator_size_class_map.h
@@ -24,7 +24,7 @@
// E.g. with kNumBits==3 all size classes after 2^kMidSizeLog
// look like 0b1xx0..0, where x is either 0 or 1.
//
-// Example: kNumBits=3, kMidSizeLog=4, kMidSizeLog=8, kMaxSizeLog=17:
+// Example: kNumBits=3, kMinSizeLog=4, kMidSizeLog=8, kMaxSizeLog=17:
//
// Classes 1 - 16 correspond to sizes 16 to 256 (size = class_id * 16).
// Next 4 classes: 256 + i * 64 (i = 1 to 4).
diff --git a/libsanitizer/sanitizer_common/sanitizer_atomic_clang_mips.h b/libsanitizer/sanitizer_common/sanitizer_atomic_clang_mips.h
index 59155e9883e..2b39097112d 100644
--- a/libsanitizer/sanitizer_common/sanitizer_atomic_clang_mips.h
+++ b/libsanitizer/sanitizer_common/sanitizer_atomic_clang_mips.h
@@ -41,7 +41,7 @@ inline atomic_uint64_t::Type atomic_fetch_add(volatile atomic_uint64_t *ptr,
atomic_uint64_t::Type val,
memory_order mo) {
DCHECK(mo &
- (memory_order_relaxed | memory_order_releasae | memory_order_seq_cst));
+ (memory_order_relaxed | memory_order_release | memory_order_seq_cst));
DCHECK(!((uptr)ptr % sizeof(*ptr)));
atomic_uint64_t::Type ret;
@@ -67,7 +67,7 @@ inline bool atomic_compare_exchange_strong(volatile atomic_uint64_t *ptr,
atomic_uint64_t::Type xchg,
memory_order mo) {
DCHECK(mo &
- (memory_order_relaxed | memory_order_releasae | memory_order_seq_cst));
+ (memory_order_relaxed | memory_order_release | memory_order_seq_cst));
DCHECK(!((uptr)ptr % sizeof(*ptr)));
typedef atomic_uint64_t::Type Type;
@@ -90,7 +90,7 @@ template <>
inline atomic_uint64_t::Type atomic_load(const volatile atomic_uint64_t *ptr,
memory_order mo) {
DCHECK(mo &
- (memory_order_relaxed | memory_order_releasae | memory_order_seq_cst));
+ (memory_order_relaxed | memory_order_release | memory_order_seq_cst));
DCHECK(!((uptr)ptr % sizeof(*ptr)));
atomic_uint64_t::Type zero = 0;
@@ -103,7 +103,7 @@ template <>
inline void atomic_store(volatile atomic_uint64_t *ptr, atomic_uint64_t::Type v,
memory_order mo) {
DCHECK(mo &
- (memory_order_relaxed | memory_order_releasae | memory_order_seq_cst));
+ (memory_order_relaxed | memory_order_release | memory_order_seq_cst));
DCHECK(!((uptr)ptr % sizeof(*ptr)));
__spin_lock(&lock.lock);
diff --git a/libsanitizer/sanitizer_common/sanitizer_chained_origin_depot.cpp b/libsanitizer/sanitizer_common/sanitizer_chained_origin_depot.cpp
new file mode 100644
index 00000000000..250ac39e130
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_chained_origin_depot.cpp
@@ -0,0 +1,108 @@
+//===-- sanitizer_chained_origin_depot.cpp --------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// A storage for chained origins.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_chained_origin_depot.h"
+
+namespace __sanitizer {
+
+bool ChainedOriginDepot::ChainedOriginDepotNode::eq(
+ u32 hash, const args_type &args) const {
+ return here_id == args.here_id && prev_id == args.prev_id;
+}
+
+uptr ChainedOriginDepot::ChainedOriginDepotNode::storage_size(
+ const args_type &args) {
+ return sizeof(ChainedOriginDepotNode);
+}
+
+/* This is murmur2 hash for the 64->32 bit case.
+ It does not behave all that well because the keys have a very biased
+ distribution (I've seen 7-element buckets with the table only 14% full).
+
+ here_id is built of
+ * (1 bits) Reserved, zero.
+ * (8 bits) Part id = bits 13..20 of the hash value of here_id's key.
+ * (23 bits) Sequential number (each part has each own sequence).
+
+ prev_id has either the same distribution as here_id (but with 3:8:21)
+ split, or one of two reserved values (-1) or (-2). Either case can
+ dominate depending on the workload.
+*/
+u32 ChainedOriginDepot::ChainedOriginDepotNode::hash(const args_type &args) {
+ const u32 m = 0x5bd1e995;
+ const u32 seed = 0x9747b28c;
+ const u32 r = 24;
+ u32 h = seed;
+ u32 k = args.here_id;
+ k *= m;
+ k ^= k >> r;
+ k *= m;
+ h *= m;
+ h ^= k;
+
+ k = args.prev_id;
+ k *= m;
+ k ^= k >> r;
+ k *= m;
+ h *= m;
+ h ^= k;
+
+ h ^= h >> 13;
+ h *= m;
+ h ^= h >> 15;
+ return h;
+}
+
+bool ChainedOriginDepot::ChainedOriginDepotNode::is_valid(
+ const args_type &args) {
+ return true;
+}
+
+void ChainedOriginDepot::ChainedOriginDepotNode::store(const args_type &args,
+ u32 other_hash) {
+ here_id = args.here_id;
+ prev_id = args.prev_id;
+}
+
+ChainedOriginDepot::ChainedOriginDepotNode::args_type
+ChainedOriginDepot::ChainedOriginDepotNode::load() const {
+ args_type ret = {here_id, prev_id};
+ return ret;
+}
+
+ChainedOriginDepot::ChainedOriginDepotNode::Handle
+ChainedOriginDepot::ChainedOriginDepotNode::get_handle() {
+ return Handle(this);
+}
+
+ChainedOriginDepot::ChainedOriginDepot() {}
+
+StackDepotStats *ChainedOriginDepot::GetStats() { return depot.GetStats(); }
+
+bool ChainedOriginDepot::Put(u32 here_id, u32 prev_id, u32 *new_id) {
+ ChainedOriginDepotDesc desc = {here_id, prev_id};
+ bool inserted;
+ ChainedOriginDepotNode::Handle h = depot.Put(desc, &inserted);
+ *new_id = h.valid() ? h.id() : 0;
+ return inserted;
+}
+
+u32 ChainedOriginDepot::Get(u32 id, u32 *other) {
+ ChainedOriginDepotDesc desc = depot.Get(id);
+ *other = desc.prev_id;
+ return desc.here_id;
+}
+
+void ChainedOriginDepot::LockAll() { depot.LockAll(); }
+
+void ChainedOriginDepot::UnlockAll() { depot.UnlockAll(); }
+
+} // namespace __sanitizer
diff --git a/libsanitizer/sanitizer_common/sanitizer_chained_origin_depot.h b/libsanitizer/sanitizer_common/sanitizer_chained_origin_depot.h
new file mode 100644
index 00000000000..453cdf6b544
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_chained_origin_depot.h
@@ -0,0 +1,88 @@
+//===-- sanitizer_chained_origin_depot.h ------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// A storage for chained origins.
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_CHAINED_ORIGIN_DEPOT_H
+#define SANITIZER_CHAINED_ORIGIN_DEPOT_H
+
+#include "sanitizer_common.h"
+#include "sanitizer_stackdepotbase.h"
+
+namespace __sanitizer {
+
+class ChainedOriginDepot {
+ public:
+ ChainedOriginDepot();
+
+ // Gets the statistic of the origin chain storage.
+ StackDepotStats *GetStats();
+
+ // Stores a chain with StackDepot ID here_id and previous chain ID prev_id.
+ // If successful, returns true and the new chain id new_id.
+ // If the same element already exists, returns false and sets new_id to the
+ // existing ID.
+ bool Put(u32 here_id, u32 prev_id, u32 *new_id);
+
+ // Retrieves the stored StackDepot ID for the given origin ID.
+ u32 Get(u32 id, u32 *other);
+
+ void LockAll();
+ void UnlockAll();
+
+ private:
+ struct ChainedOriginDepotDesc {
+ u32 here_id;
+ u32 prev_id;
+ };
+
+ struct ChainedOriginDepotNode {
+ ChainedOriginDepotNode *link;
+ u32 id;
+ u32 here_id;
+ u32 prev_id;
+
+ typedef ChainedOriginDepotDesc args_type;
+
+ bool eq(u32 hash, const args_type &args) const;
+
+ static uptr storage_size(const args_type &args);
+
+ static u32 hash(const args_type &args);
+
+ static bool is_valid(const args_type &args);
+
+ void store(const args_type &args, u32 other_hash);
+
+ args_type load() const;
+
+ struct Handle {
+ ChainedOriginDepotNode *node_;
+ Handle() : node_(nullptr) {}
+ explicit Handle(ChainedOriginDepotNode *node) : node_(node) {}
+ bool valid() { return node_; }
+ u32 id() { return node_->id; }
+ int here_id() { return node_->here_id; }
+ int prev_id() { return node_->prev_id; }
+ };
+
+ Handle get_handle();
+
+ typedef Handle handle_type;
+ };
+
+ StackDepotBase<ChainedOriginDepotNode, 4, 20> depot;
+
+ ChainedOriginDepot(const ChainedOriginDepot &) = delete;
+ void operator=(const ChainedOriginDepot &) = delete;
+};
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_CHAINED_ORIGIN_DEPOT_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_common.cpp b/libsanitizer/sanitizer_common/sanitizer_common.cpp
index 87efda5bd37..33960d94a2f 100644
--- a/libsanitizer/sanitizer_common/sanitizer_common.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_common.cpp
@@ -87,7 +87,7 @@ const char *StripModuleName(const char *module) {
void ReportErrorSummary(const char *error_message, const char *alt_tool_name) {
if (!common_flags()->print_summary)
return;
- InternalScopedString buff(kMaxSummaryLength);
+ InternalScopedString buff;
buff.append("SUMMARY: %s: %s",
alt_tool_name ? alt_tool_name : SanitizerToolName, error_message);
__sanitizer_report_error_summary(buff.data());
@@ -274,6 +274,14 @@ uptr ReadBinaryNameCached(/*out*/char *buf, uptr buf_len) {
return name_len;
}
+uptr ReadBinaryDir(/*out*/ char *buf, uptr buf_len) {
+ ReadBinaryNameCached(buf, buf_len);
+ const char *exec_name_pos = StripModuleName(buf);
+ uptr name_len = exec_name_pos - buf;
+ buf[name_len] = '\0';
+ return name_len;
+}
+
#if !SANITIZER_GO
void PrintCmdline() {
char **argv = GetArgv();
diff --git a/libsanitizer/sanitizer_common/sanitizer_common.h b/libsanitizer/sanitizer_common/sanitizer_common.h
index bce24d68045..7b65dd7dfb8 100644
--- a/libsanitizer/sanitizer_common/sanitizer_common.h
+++ b/libsanitizer/sanitizer_common/sanitizer_common.h
@@ -44,7 +44,7 @@ const uptr kMaxPathLength = 4096;
const uptr kMaxThreadStackSize = 1 << 30; // 1Gb
-static const uptr kErrorMessageBufferSize = 1 << 16;
+const uptr kErrorMessageBufferSize = 1 << 16;
// Denotes fake PC values that come from JIT/JAVA/etc.
// For such PC values __tsan_symbolize_external_ex() will be called.
@@ -135,6 +135,15 @@ void UnmapFromTo(uptr from, uptr to);
uptr MapDynamicShadow(uptr shadow_size_bytes, uptr shadow_scale,
uptr min_shadow_base_alignment, uptr &high_mem_end);
+// Let S = max(shadow_size, num_aliases * alias_size, ring_buffer_size).
+// Reserves 2*S bytes of address space to the right of the returned address and
+// ring_buffer_size bytes to the left. The returned address is aligned to 2*S.
+// Also creates num_aliases regions of accessible memory starting at offset S
+// from the returned address. Each region has size alias_size and is backed by
+// the same physical memory.
+uptr MapDynamicShadowAndAliases(uptr shadow_size, uptr alias_size,
+ uptr num_aliases, uptr ring_buffer_size);
+
// Reserve memory range [beg, end]. If madvise_shadow is true then apply
// madvise (e.g. hugepages, core dumping) requested by options.
void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name,
@@ -248,6 +257,7 @@ const char *StripModuleName(const char *module);
// OS
uptr ReadBinaryName(/*out*/char *buf, uptr buf_len);
uptr ReadBinaryNameCached(/*out*/char *buf, uptr buf_len);
+uptr ReadBinaryDir(/*out*/ char *buf, uptr buf_len);
uptr ReadLongProcessName(/*out*/ char *buf, uptr buf_len);
const char *GetProcessName();
void UpdateProcessName();
@@ -294,8 +304,8 @@ void NORETURN ReportMmapFailureAndDie(uptr size, const char *mem_type,
const char *mmap_type, error_t err,
bool raw_report = false);
-// Specific tools may override behavior of "Die" and "CheckFailed" functions
-// to do tool-specific job.
+// Specific tools may override behavior of "Die" function to do tool-specific
+// job.
typedef void (*DieCallbackType)(void);
// It's possible to add several callbacks that would be run when "Die" is
@@ -307,9 +317,7 @@ bool RemoveDieCallback(DieCallbackType callback);
void SetUserDieCallback(DieCallbackType callback);
-typedef void (*CheckFailedCallbackType)(const char *, int, const char *,
- u64, u64);
-void SetCheckFailedCallback(CheckFailedCallbackType callback);
+void SetCheckUnwindCallback(void (*callback)());
// Callback will be called if soft_rss_limit_mb is given and the limit is
// exceeded (exceeded==true) or if rss went down below the limit
@@ -343,8 +351,6 @@ void ReportDeadlySignal(const SignalContext &sig, u32 tid,
void SetAlternateSignalStack();
void UnsetAlternateSignalStack();
-// 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.
@@ -441,8 +447,14 @@ inline uptr Log2(uptr x) {
// Don't use std::min, std::max or std::swap, to minimize dependency
// on libstdc++.
-template<class T> T Min(T a, T b) { return a < b ? a : b; }
-template<class T> T Max(T a, T b) { return a > b ? a : b; }
+template <class T>
+constexpr T Min(T a, T b) {
+ return a < b ? a : b;
+}
+template <class T>
+constexpr T Max(T a, T b) {
+ return a > b ? a : b;
+}
template<class T> void Swap(T& a, T& b) {
T tmp = a;
a = b;
@@ -467,6 +479,7 @@ inline int ToLower(int c) {
template<typename T>
class InternalMmapVectorNoCtor {
public:
+ using value_type = T;
void Initialize(uptr initial_capacity) {
capacity_bytes_ = 0;
size_ = 0;
@@ -590,21 +603,21 @@ class InternalMmapVector : public InternalMmapVectorNoCtor<T> {
InternalMmapVector &operator=(InternalMmapVector &&) = delete;
};
-class InternalScopedString : public InternalMmapVector<char> {
+class InternalScopedString {
public:
- explicit InternalScopedString(uptr max_length)
- : InternalMmapVector<char>(max_length), length_(0) {
- (*this)[0] = '\0';
- }
- uptr length() { return length_; }
+ InternalScopedString() : buffer_(1) { buffer_[0] = '\0'; }
+
+ uptr length() const { return buffer_.size() - 1; }
void clear() {
- (*this)[0] = '\0';
- length_ = 0;
+ buffer_.resize(1);
+ buffer_[0] = '\0';
}
void append(const char *format, ...);
+ const char *data() const { return buffer_.data(); }
+ char *data() { return buffer_.data(); }
private:
- uptr length_;
+ InternalMmapVector<char> buffer_;
};
template <class T>
@@ -651,9 +664,13 @@ void Sort(T *v, uptr size, Compare comp = {}) {
// Works like std::lower_bound: finds the first element that is not less
// than the val.
-template <class Container, class Value, class Compare>
-uptr InternalLowerBound(const Container &v, uptr first, uptr last,
- const Value &val, Compare comp) {
+template <class Container,
+ class Compare = CompareLess<typename Container::value_type>>
+uptr InternalLowerBound(const Container &v,
+ const typename Container::value_type &val,
+ Compare comp = {}) {
+ uptr first = 0;
+ uptr last = v.size();
while (last > first) {
uptr mid = (first + last) / 2;
if (comp(v[mid], val))
@@ -677,6 +694,27 @@ enum ModuleArch {
kModuleArchRISCV64
};
+// Sorts and removes duplicates from the container.
+template <class Container,
+ class Compare = CompareLess<typename Container::value_type>>
+void SortAndDedup(Container &v, Compare comp = {}) {
+ Sort(v.data(), v.size(), comp);
+ uptr size = v.size();
+ if (size < 2)
+ return;
+ uptr last = 0;
+ for (uptr i = 1; i < size; ++i) {
+ if (comp(v[last], v[i])) {
+ ++last;
+ if (last != i)
+ v[last] = v[i];
+ } else {
+ CHECK(!comp(v[i], v[last]));
+ }
+ }
+ v.resize(last + 1);
+}
+
// Opens the file 'file_name" and reads up to 'max_len' bytes.
// The resulting buffer is mmaped and stored in '*buff'.
// Returns true if file was successfully opened and read.
diff --git a/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc b/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc
index 2f2787e283a..7867fccde39 100644
--- a/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc
+++ b/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc
@@ -239,7 +239,7 @@ extern const short *_tolower_tab_;
COMMON_INTERCEPT_FUNCTION(fn)
#endif
-#ifdef __GLIBC__
+#if SANITIZER_GLIBC
// If we could not find the versioned symbol, fall back to an unversioned
// lookup. This is needed to work around a GLibc bug that causes dlsym
// with RTLD_NEXT to return the oldest versioned symbol.
@@ -2195,6 +2195,7 @@ INTERCEPTOR(int, clock_gettime, u32 clk_id, void *tp) {
}
return res;
}
+#if SANITIZER_GLIBC
namespace __sanitizer {
extern "C" {
int real_clock_gettime(u32 clk_id, void *tp) {
@@ -2204,6 +2205,7 @@ int real_clock_gettime(u32 clk_id, void *tp) {
}
} // extern "C"
} // namespace __sanitizer
+#endif
INTERCEPTOR(int, clock_settime, u32 clk_id, const void *tp) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, clock_settime, clk_id, tp);
@@ -3355,7 +3357,7 @@ INTERCEPTOR(char *, setlocale, int category, char *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);
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, REAL(strlen)(res) + 1);
unpoison_ctype_arrays(ctx);
}
return res;
@@ -4030,7 +4032,7 @@ INTERCEPTOR(int, sigwait, __sanitizer_sigset_t *set, int *sig) {
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
// https://github.com/google/sanitizers/issues/321.
- int res = REAL(sigwait)(set, sig);
+ int res = COMMON_INTERCEPTOR_BLOCK_REAL(sigwait)(set, sig);
if (!res && sig) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sig, sizeof(*sig));
return res;
}
@@ -4047,7 +4049,7 @@ INTERCEPTOR(int, sigwaitinfo, __sanitizer_sigset_t *set, void *info) {
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
// https://github.com/google/sanitizers/issues/321.
- int res = REAL(sigwaitinfo)(set, info);
+ int res = COMMON_INTERCEPTOR_BLOCK_REAL(sigwaitinfo)(set, info);
if (res > 0 && info) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, info, siginfo_t_sz);
return res;
}
@@ -4066,7 +4068,7 @@ INTERCEPTOR(int, sigtimedwait, __sanitizer_sigset_t *set, void *info,
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
// https://github.com/google/sanitizers/issues/321.
- int res = REAL(sigtimedwait)(set, info, timeout);
+ int res = COMMON_INTERCEPTOR_BLOCK_REAL(sigtimedwait)(set, info, timeout);
if (res > 0 && info) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, info, siginfo_t_sz);
return res;
}
@@ -5995,6 +5997,9 @@ void unpoison_file(__sanitizer_FILE *fp) {
if (fp->_IO_read_base && fp->_IO_read_base < fp->_IO_read_end)
COMMON_INTERCEPTOR_INITIALIZE_RANGE(fp->_IO_read_base,
fp->_IO_read_end - fp->_IO_read_base);
+ if (fp->_IO_write_base && fp->_IO_write_base < fp->_IO_write_end)
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(fp->_IO_write_base,
+ fp->_IO_write_end - fp->_IO_write_base);
#endif
#endif // SANITIZER_HAS_STRUCT_FILE
}
@@ -6221,6 +6226,8 @@ INTERCEPTOR(void, _obstack_newchunk, __sanitizer_obstack *obstack, int length) {
INTERCEPTOR(int, fflush, __sanitizer_FILE *fp) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, fflush, fp);
+ if (fp)
+ unpoison_file(fp);
int res = REAL(fflush)(fp);
// FIXME: handle fp == NULL
if (fp) {
@@ -6240,6 +6247,8 @@ INTERCEPTOR(int, fclose, __sanitizer_FILE *fp) {
COMMON_INTERCEPTOR_ENTER(ctx, fclose, fp);
COMMON_INTERCEPTOR_FILE_CLOSE(ctx, fp);
const FileMetadata *m = GetInterceptorMetadata(fp);
+ if (fp)
+ unpoison_file(fp);
int res = REAL(fclose)(fp);
if (m) {
COMMON_INTERCEPTOR_INITIALIZE_RANGE(*m->addr, *m->size);
diff --git a/libsanitizer/sanitizer_common/sanitizer_common_interceptors_ioctl.inc b/libsanitizer/sanitizer_common/sanitizer_common_interceptors_ioctl.inc
index 490a04b2181..7f181258eab 100644
--- a/libsanitizer/sanitizer_common/sanitizer_common_interceptors_ioctl.inc
+++ b/libsanitizer/sanitizer_common/sanitizer_common_interceptors_ioctl.inc
@@ -330,13 +330,17 @@ static void ioctl_table_fill() {
_(SOUND_PCM_WRITE_CHANNELS, WRITE, sizeof(int));
_(SOUND_PCM_WRITE_FILTER, WRITE, sizeof(int));
_(TCFLSH, NONE, 0);
+#if SANITIZER_GLIBC
_(TCGETA, WRITE, struct_termio_sz);
+#endif
_(TCGETS, WRITE, struct_termios_sz);
_(TCSBRK, NONE, 0);
_(TCSBRKP, NONE, 0);
+#if SANITIZER_GLIBC
_(TCSETA, READ, struct_termio_sz);
_(TCSETAF, READ, struct_termio_sz);
_(TCSETAW, READ, struct_termio_sz);
+#endif
_(TCSETS, READ, struct_termios_sz);
_(TCSETSF, READ, struct_termios_sz);
_(TCSETSW, READ, struct_termios_sz);
@@ -364,7 +368,7 @@ static void ioctl_table_fill() {
_(VT_WAITACTIVE, NONE, 0);
#endif
-#if SANITIZER_LINUX && !SANITIZER_ANDROID
+#if SANITIZER_GLIBC
// _(SIOCDEVPLIP, WRITE, struct_ifreq_sz); // the same as EQL_ENSLAVE
_(CYGETDEFTHRESH, WRITE, sizeof(int));
_(CYGETDEFTIMEOUT, WRITE, sizeof(int));
diff --git a/libsanitizer/sanitizer_common/sanitizer_common_interceptors_vfork_aarch64.inc.S b/libsanitizer/sanitizer_common/sanitizer_common_interceptors_vfork_aarch64.inc.S
index 20f42f1ea94..72e482754b6 100644
--- a/libsanitizer/sanitizer_common/sanitizer_common_interceptors_vfork_aarch64.inc.S
+++ b/libsanitizer/sanitizer_common/sanitizer_common_interceptors_vfork_aarch64.inc.S
@@ -1,6 +1,7 @@
#if defined(__aarch64__) && defined(__linux__)
#include "sanitizer_common/sanitizer_asm.h"
+#include "builtins/assembly.h"
ASM_HIDDEN(COMMON_INTERCEPTOR_SPILL_AREA)
@@ -9,6 +10,7 @@ ASM_HIDDEN(COMMON_INTERCEPTOR_SPILL_AREA)
ASM_TYPE_FUNCTION(ASM_WRAPPER_NAME(vfork))
ASM_WRAPPER_NAME(vfork):
// Save x30 in the off-stack spill area.
+ hint #25 // paciasp
stp xzr, x30, [sp, #-16]!
bl COMMON_INTERCEPTOR_SPILL_AREA
ldp xzr, x30, [sp], 16
@@ -33,6 +35,7 @@ ASM_WRAPPER_NAME(vfork):
bl COMMON_INTERCEPTOR_SPILL_AREA
ldr x30, [x0]
ldp x0, xzr, [sp], 16
+ hint #29 // autiasp
ret
ASM_SIZE(vfork)
@@ -40,4 +43,6 @@ ASM_SIZE(vfork)
.weak vfork
.set vfork, ASM_WRAPPER_NAME(vfork)
+GNU_PROPERTY_BTI_PAC
+
#endif
diff --git a/libsanitizer/sanitizer_common/sanitizer_common_interface.inc b/libsanitizer/sanitizer_common/sanitizer_common_interface.inc
index c78b6e10b68..932e5478616 100644
--- a/libsanitizer/sanitizer_common/sanitizer_common_interface.inc
+++ b/libsanitizer/sanitizer_common/sanitizer_common_interface.inc
@@ -13,6 +13,7 @@ INTERFACE_FUNCTION(__sanitizer_contiguous_container_find_bad_address)
INTERFACE_FUNCTION(__sanitizer_set_death_callback)
INTERFACE_FUNCTION(__sanitizer_set_report_path)
INTERFACE_FUNCTION(__sanitizer_set_report_fd)
+INTERFACE_FUNCTION(__sanitizer_get_report_path)
INTERFACE_FUNCTION(__sanitizer_verify_contiguous_container)
INTERFACE_WEAK_FUNCTION(__sanitizer_on_print)
INTERFACE_WEAK_FUNCTION(__sanitizer_report_error_summary)
diff --git a/libsanitizer/sanitizer_common/sanitizer_common_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_common_libcdep.cpp
index 047c5a17ea6..1037938f3d3 100644
--- a/libsanitizer/sanitizer_common/sanitizer_common_libcdep.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_common_libcdep.cpp
@@ -92,14 +92,13 @@ void *BackgroundThread(void *arg) {
#endif
void WriteToSyslog(const char *msg) {
- InternalScopedString msg_copy(kErrorMessageBufferSize);
+ InternalScopedString msg_copy;
msg_copy.append("%s", msg);
- char *p = msg_copy.data();
- char *q;
+ const char *p = msg_copy.data();
// Print one line at a time.
// syslog, at least on Android, has an implicit message length limit.
- while ((q = internal_strchr(p, '\n'))) {
+ while (char* q = internal_strchr(p, '\n')) {
*q = '\0';
WriteOneLineToSyslog(p);
p = q + 1;
diff --git a/libsanitizer/sanitizer_common/sanitizer_file.cpp b/libsanitizer/sanitizer_common/sanitizer_file.cpp
index 7cce60906b7..0b92dccde4a 100644
--- a/libsanitizer/sanitizer_common/sanitizer_file.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_file.cpp
@@ -58,6 +58,9 @@ void ReportFile::ReopenIfNecessary() {
} else {
internal_snprintf(full_path, kMaxPathLength, "%s.%zu", path_prefix, pid);
}
+ if (common_flags()->log_suffix) {
+ internal_strlcat(full_path, common_flags()->log_suffix, kMaxPathLength);
+ }
error_t err;
fd = OpenFile(full_path, WrOnly, &err);
if (fd == kInvalidFd) {
@@ -95,6 +98,12 @@ void ReportFile::SetReportPath(const char *path) {
}
}
+const char *ReportFile::GetReportPath() {
+ SpinMutexLock l(mu);
+ ReopenIfNecessary();
+ return full_path;
+}
+
bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size,
uptr *read_len, uptr max_len, error_t *errno_p) {
*buff = nullptr;
@@ -213,6 +222,10 @@ void __sanitizer_set_report_fd(void *fd) {
report_file.fd = (fd_t)reinterpret_cast<uptr>(fd);
report_file.fd_pid = internal_getpid();
}
+
+const char *__sanitizer_get_report_path() {
+ return report_file.GetReportPath();
+}
} // extern "C"
#endif // !SANITIZER_FUCHSIA
diff --git a/libsanitizer/sanitizer_common/sanitizer_file.h b/libsanitizer/sanitizer_common/sanitizer_file.h
index 26681f0493d..08671ab67d0 100644
--- a/libsanitizer/sanitizer_common/sanitizer_file.h
+++ b/libsanitizer/sanitizer_common/sanitizer_file.h
@@ -26,6 +26,7 @@ struct ReportFile {
void Write(const char *buffer, uptr length);
bool SupportsColors();
void SetReportPath(const char *path);
+ const char *GetReportPath();
// Don't use fields directly. They are only declared public to allow
// aggregate initialization.
diff --git a/libsanitizer/sanitizer_common/sanitizer_flags.cpp b/libsanitizer/sanitizer_common/sanitizer_flags.cpp
index 21048be7304..d52e96a7c38 100644
--- a/libsanitizer/sanitizer_common/sanitizer_flags.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_flags.cpp
@@ -35,6 +35,7 @@ void CommonFlags::CopyFrom(const CommonFlags &other) {
// Copy the string from "s" to "out", making the following substitutions:
// %b = binary basename
// %p = pid
+// %d = binary directory
void SubstituteForFlagValue(const char *s, char *out, uptr out_size) {
char *out_end = out + out_size;
while (*s && out < out_end - 1) {
@@ -64,6 +65,12 @@ void SubstituteForFlagValue(const char *s, char *out, uptr out_size) {
s += 2; // skip "%p"
break;
}
+ case 'd': {
+ uptr len = ReadBinaryDir(out, out_end - out);
+ out += len;
+ s += 2; // skip "%d"
+ break;
+ }
default:
*out++ = *s++;
break;
diff --git a/libsanitizer/sanitizer_common/sanitizer_flags.inc b/libsanitizer/sanitizer_common/sanitizer_flags.inc
index cfb5822645f..3bc44c6b1eb 100644
--- a/libsanitizer/sanitizer_common/sanitizer_flags.inc
+++ b/libsanitizer/sanitizer_common/sanitizer_flags.inc
@@ -59,6 +59,8 @@ COMMON_FLAG(
bool, log_exe_name, false,
"Mention name of executable when reporting error and "
"append executable name to logs (as in \"log_path.exe_name.pid\").")
+COMMON_FLAG(const char *, log_suffix, nullptr,
+ "String to append to log file name, e.g. \".txt\".")
COMMON_FLAG(
bool, log_to_syslog, (bool)SANITIZER_ANDROID || (bool)SANITIZER_MAC,
"Write all sanitizer output to syslog in addition to other means of "
diff --git a/libsanitizer/sanitizer_common/sanitizer_fuchsia.cpp b/libsanitizer/sanitizer_common/sanitizer_fuchsia.cpp
index 7200ffdac0f..4f692f99c20 100644
--- a/libsanitizer/sanitizer_common/sanitizer_fuchsia.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_fuchsia.cpp
@@ -14,7 +14,6 @@
#include "sanitizer_fuchsia.h"
#if SANITIZER_FUCHSIA
-#include <limits.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
@@ -69,9 +68,7 @@ uptr internal_getpid() {
return pid;
}
-int internal_dlinfo(void *handle, int request, void *p) {
- UNIMPLEMENTED();
-}
+int internal_dlinfo(void *handle, int request, void *p) { UNIMPLEMENTED(); }
uptr GetThreadSelf() { return reinterpret_cast<uptr>(thrd_current()); }
@@ -153,9 +150,9 @@ void BlockingMutex::CheckLocked() {
CHECK_NE(MtxUnlocked, atomic_load(m, memory_order_relaxed));
}
-uptr GetPageSize() { return PAGE_SIZE; }
+uptr GetPageSize() { return _zx_system_get_page_size(); }
-uptr GetMmapGranularity() { return PAGE_SIZE; }
+uptr GetMmapGranularity() { return _zx_system_get_page_size(); }
sanitizer_shadow_bounds_t ShadowBounds;
@@ -168,7 +165,7 @@ uptr GetMaxVirtualAddress() { return GetMaxUserVirtualAddress(); }
static void *DoAnonymousMmapOrDie(uptr size, const char *mem_type,
bool raw_report, bool die_for_nomem) {
- size = RoundUpTo(size, PAGE_SIZE);
+ size = RoundUpTo(size, GetPageSize());
zx_handle_t vmo;
zx_status_t status = _zx_vmo_create(size, 0, &vmo);
@@ -214,15 +211,14 @@ void *MmapOrDieOnFatalError(uptr size, const char *mem_type) {
uptr ReservedAddressRange::Init(uptr init_size, const char *name,
uptr fixed_addr) {
- init_size = RoundUpTo(init_size, PAGE_SIZE);
+ init_size = RoundUpTo(init_size, GetPageSize());
DCHECK_EQ(os_handle_, ZX_HANDLE_INVALID);
uintptr_t base;
zx_handle_t vmar;
- zx_status_t status =
- _zx_vmar_allocate(
- _zx_vmar_root_self(),
- ZX_VM_CAN_MAP_READ | ZX_VM_CAN_MAP_WRITE | ZX_VM_CAN_MAP_SPECIFIC,
- 0, init_size, &vmar, &base);
+ zx_status_t status = _zx_vmar_allocate(
+ _zx_vmar_root_self(),
+ ZX_VM_CAN_MAP_READ | ZX_VM_CAN_MAP_WRITE | ZX_VM_CAN_MAP_SPECIFIC, 0,
+ init_size, &vmar, &base);
if (status != ZX_OK)
ReportMmapFailureAndDie(init_size, name, "zx_vmar_allocate", status);
base_ = reinterpret_cast<void *>(base);
@@ -236,7 +232,7 @@ uptr ReservedAddressRange::Init(uptr init_size, const char *name,
static uptr DoMmapFixedOrDie(zx_handle_t vmar, uptr fixed_addr, uptr map_size,
void *base, const char *name, bool die_for_nomem) {
uptr offset = fixed_addr - reinterpret_cast<uptr>(base);
- map_size = RoundUpTo(map_size, PAGE_SIZE);
+ map_size = RoundUpTo(map_size, GetPageSize());
zx_handle_t vmo;
zx_status_t status = _zx_vmo_create(map_size, 0, &vmo);
if (status != ZX_OK) {
@@ -264,19 +260,19 @@ static uptr DoMmapFixedOrDie(zx_handle_t vmar, uptr fixed_addr, uptr map_size,
uptr ReservedAddressRange::Map(uptr fixed_addr, uptr map_size,
const char *name) {
- return DoMmapFixedOrDie(os_handle_, fixed_addr, map_size, base_,
- name_, false);
+ return DoMmapFixedOrDie(os_handle_, fixed_addr, map_size, base_, name_,
+ false);
}
uptr ReservedAddressRange::MapOrDie(uptr fixed_addr, uptr map_size,
const char *name) {
- return DoMmapFixedOrDie(os_handle_, fixed_addr, map_size, base_,
- name_, true);
+ return DoMmapFixedOrDie(os_handle_, fixed_addr, map_size, base_, name_, true);
}
void UnmapOrDieVmar(void *addr, uptr size, zx_handle_t target_vmar) {
- if (!addr || !size) return;
- size = RoundUpTo(size, PAGE_SIZE);
+ if (!addr || !size)
+ return;
+ size = RoundUpTo(size, GetPageSize());
zx_status_t status =
_zx_vmar_unmap(target_vmar, reinterpret_cast<uintptr_t>(addr), size);
@@ -316,7 +312,7 @@ void *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name) {
void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment,
const char *mem_type) {
- CHECK_GE(size, PAGE_SIZE);
+ CHECK_GE(size, GetPageSize());
CHECK(IsPowerOfTwo(size));
CHECK(IsPowerOfTwo(alignment));
@@ -356,7 +352,8 @@ void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment,
_zx_vmar_root_self(),
ZX_VM_PERM_READ | ZX_VM_PERM_WRITE | ZX_VM_SPECIFIC_OVERWRITE,
addr - info.base, vmo, 0, size, &new_addr);
- if (status == ZX_OK) CHECK_EQ(new_addr, addr);
+ if (status == ZX_OK)
+ CHECK_EQ(new_addr, addr);
}
}
if (status == ZX_OK && addr != map_addr)
@@ -381,9 +378,18 @@ void UnmapOrDie(void *addr, uptr size) {
UnmapOrDieVmar(addr, size, _zx_vmar_root_self());
}
-// This is used on the shadow mapping, which cannot be changed.
-// Zircon doesn't have anything like MADV_DONTNEED.
-void ReleaseMemoryPagesToOS(uptr beg, uptr end) {}
+void ReleaseMemoryPagesToOS(uptr beg, uptr end) {
+ uptr beg_aligned = RoundUpTo(beg, GetPageSize());
+ uptr end_aligned = RoundDownTo(end, GetPageSize());
+ if (beg_aligned < end_aligned) {
+ zx_handle_t root_vmar = _zx_vmar_root_self();
+ CHECK_NE(root_vmar, ZX_HANDLE_INVALID);
+ zx_status_t status =
+ _zx_vmar_op_range(root_vmar, ZX_VMAR_OP_DECOMMIT, beg_aligned,
+ end_aligned - beg_aligned, nullptr, 0);
+ CHECK_EQ(status, ZX_OK);
+ }
+}
void DumpProcessMap() {
// TODO(mcgrathr): write it
@@ -412,8 +418,9 @@ bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size,
uint64_t vmo_size;
status = _zx_vmo_get_size(vmo, &vmo_size);
if (status == ZX_OK) {
- if (vmo_size < max_len) max_len = vmo_size;
- size_t map_size = RoundUpTo(max_len, PAGE_SIZE);
+ if (vmo_size < max_len)
+ max_len = vmo_size;
+ size_t map_size = RoundUpTo(max_len, GetPageSize());
uintptr_t addr;
status = _zx_vmar_map(_zx_vmar_root_self(), ZX_VM_PERM_READ, 0, vmo, 0,
map_size, &addr);
@@ -425,7 +432,8 @@ bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size,
}
_zx_handle_close(vmo);
}
- if (status != ZX_OK && errno_p) *errno_p = status;
+ if (status != ZX_OK && errno_p)
+ *errno_p = status;
return status == ZX_OK;
}
@@ -499,9 +507,7 @@ bool GetRandom(void *buffer, uptr length, bool blocking) {
return true;
}
-u32 GetNumberOfCPUs() {
- return zx_system_get_num_cpus();
-}
+u32 GetNumberOfCPUs() { return zx_system_get_num_cpus(); }
uptr GetRSS() { UNIMPLEMENTED(); }
@@ -529,6 +535,10 @@ void __sanitizer_set_report_path(const char *path) {
void __sanitizer_set_report_fd(void *fd) {
UNREACHABLE("not available on Fuchsia");
}
+
+const char *__sanitizer_get_report_path() {
+ UNREACHABLE("not available on Fuchsia");
+}
} // extern "C"
#endif // SANITIZER_FUCHSIA
diff --git a/libsanitizer/sanitizer_common/sanitizer_interface_internal.h b/libsanitizer/sanitizer_common/sanitizer_interface_internal.h
index be8023e9e16..0b001c1c483 100644
--- a/libsanitizer/sanitizer_common/sanitizer_interface_internal.h
+++ b/libsanitizer/sanitizer_common/sanitizer_interface_internal.h
@@ -28,6 +28,10 @@ extern "C" {
// (casted to void *).
SANITIZER_INTERFACE_ATTRIBUTE
void __sanitizer_set_report_fd(void *fd);
+ // Get the current full report file path, if a path was specified by
+ // an earlier call to __sanitizer_set_report_path. Returns null otherwise.
+ SANITIZER_INTERFACE_ATTRIBUTE
+ const char *__sanitizer_get_report_path();
typedef struct {
int coverage_sandboxed;
diff --git a/libsanitizer/sanitizer_common/sanitizer_internal_defs.h b/libsanitizer/sanitizer_common/sanitizer_internal_defs.h
index d8f0540037d..84053fec264 100644
--- a/libsanitizer/sanitizer_common/sanitizer_internal_defs.h
+++ b/libsanitizer/sanitizer_common/sanitizer_internal_defs.h
@@ -409,6 +409,9 @@ inline void Trap() {
(void)enable_fp; \
} while (0)
+constexpr u32 kInvalidTid = -1;
+constexpr u32 kMainTid = 0;
+
} // namespace __sanitizer
namespace __asan {
diff --git a/libsanitizer/sanitizer_common/sanitizer_libignore.cpp b/libsanitizer/sanitizer_common/sanitizer_libignore.cpp
index 9ea19bc21fa..a65d3d896e3 100644
--- a/libsanitizer/sanitizer_common/sanitizer_libignore.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_libignore.cpp
@@ -38,7 +38,7 @@ void LibIgnore::AddIgnoredLibrary(const char *name_templ) {
void LibIgnore::OnLibraryLoaded(const char *name) {
BlockingMutexLock lock(&mutex_);
// Try to match suppressions with symlink target.
- InternalScopedString buf(kMaxPathLength);
+ InternalMmapVector<char> buf(kMaxPathLength);
if (name && internal_readlink(name, buf.data(), buf.size() - 1) > 0 &&
buf[0]) {
for (uptr i = 0; i < count_; i++) {
diff --git a/libsanitizer/sanitizer_common/sanitizer_linux.cpp b/libsanitizer/sanitizer_common/sanitizer_linux.cpp
index 379f6d9e294..b371477755f 100644
--- a/libsanitizer/sanitizer_common/sanitizer_linux.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_linux.cpp
@@ -183,6 +183,14 @@ uptr internal_munmap(void *addr, uptr length) {
return internal_syscall(SYSCALL(munmap), (uptr)addr, length);
}
+#if SANITIZER_LINUX
+uptr internal_mremap(void *old_address, uptr old_size, uptr new_size, int flags,
+ void *new_address) {
+ return internal_syscall(SYSCALL(mremap), (uptr)old_address, old_size,
+ new_size, flags, (uptr)new_address);
+}
+#endif
+
int internal_mprotect(void *addr, uptr length, int prot) {
return internal_syscall(SYSCALL(mprotect), (uptr)addr, length, prot);
}
@@ -489,22 +497,24 @@ int TgKill(pid_t pid, tid_t tid, int sig) {
}
#endif
-#if !SANITIZER_SOLARIS && !SANITIZER_NETBSD
+#if SANITIZER_GLIBC
u64 NanoTime() {
-#if SANITIZER_FREEBSD
- timeval tv;
-#else
kernel_timeval tv;
-#endif
internal_memset(&tv, 0, sizeof(tv));
internal_syscall(SYSCALL(gettimeofday), &tv, 0);
- return (u64)tv.tv_sec * 1000*1000*1000 + tv.tv_usec * 1000;
+ return (u64)tv.tv_sec * 1000 * 1000 * 1000 + tv.tv_usec * 1000;
}
-
+// Used by real_clock_gettime.
uptr internal_clock_gettime(__sanitizer_clockid_t clk_id, void *tp) {
return internal_syscall(SYSCALL(clock_gettime), clk_id, tp);
}
-#endif // !SANITIZER_SOLARIS && !SANITIZER_NETBSD
+#elif !SANITIZER_SOLARIS && !SANITIZER_NETBSD
+u64 NanoTime() {
+ struct timespec ts;
+ clock_gettime(CLOCK_REALTIME, &ts);
+ return (u64)ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
+}
+#endif
// Like getenv, but reads env directly from /proc (on Linux) or parses the
// 'environ' array (on some others) and does not use libc. This function
@@ -1334,50 +1344,42 @@ uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
#elif SANITIZER_RISCV64
uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
int *parent_tidptr, void *newtls, int *child_tidptr) {
- long long res;
if (!fn || !child_stack)
return -EINVAL;
+
CHECK_EQ(0, (uptr)child_stack % 16);
- 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 int (*__fn)(void *) __asm__("a0") = fn;
+ register int res __asm__("a0");
+ register int __flags __asm__("a0") = flags;
register void *__stack __asm__("a1") = child_stack;
- register int __flags __asm__("a2") = flags;
- register void *__arg __asm__("a3") = arg;
- register int *__ptid __asm__("a4") = parent_tidptr;
- register void *__tls __asm__("a5") = newtls;
- register int *__ctid __asm__("a6") = child_tidptr;
+ register int *__ptid __asm__("a2") = parent_tidptr;
+ register void *__tls __asm__("a3") = newtls;
+ register int *__ctid __asm__("a4") = child_tidptr;
+ register int (*__fn)(void *) __asm__("a5") = fn;
+ register void *__arg __asm__("a6") = arg;
+ register int nr_clone __asm__("a7") = __NR_clone;
__asm__ __volatile__(
- "mv a0,a2\n" /* flags */
- "mv a2,a4\n" /* ptid */
- "mv a3,a5\n" /* tls */
- "mv a4,a6\n" /* ctid */
- "addi a7, zero, %9\n" /* clone */
-
"ecall\n"
- /* if (%r0 != 0)
- * return %r0;
+ /* if (a0 != 0)
+ * return a0;
*/
"bnez a0, 1f\n"
- /* In the child, now. Call "fn(arg)". */
- "ld a0, 8(sp)\n"
- "ld a1, 16(sp)\n"
- "jalr a1\n"
+ // In the child, now. Call "fn(arg)".
+ "mv a0, a6\n"
+ "jalr a5\n"
- /* Call _exit(%r0). */
- "addi a7, zero, %10\n"
+ // Call _exit(a0).
+ "addi a7, zero, %9\n"
"ecall\n"
"1:\n"
: "=r"(res)
- : "i"(-EINVAL), "r"(__fn), "r"(__stack), "r"(__flags), "r"(__arg),
- "r"(__ptid), "r"(__tls), "r"(__ctid), "i"(__NR_clone), "i"(__NR_exit)
- : "ra", "memory");
+ : "0"(__flags), "r"(__stack), "r"(__ptid), "r"(__tls), "r"(__ctid),
+ "r"(__fn), "r"(__arg), "r"(nr_clone), "i"(__NR_exit)
+ : "memory");
return res;
}
#elif defined(__aarch64__)
diff --git a/libsanitizer/sanitizer_common/sanitizer_linux.h b/libsanitizer/sanitizer_common/sanitizer_linux.h
index 24902d1b6bc..9a23fcfb3b9 100644
--- a/libsanitizer/sanitizer_common/sanitizer_linux.h
+++ b/libsanitizer/sanitizer_common/sanitizer_linux.h
@@ -49,7 +49,9 @@ uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count);
uptr internal_sigaltstack(const void* ss, void* oss);
uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set,
__sanitizer_sigset_t *oldset);
+#if SANITIZER_GLIBC
uptr internal_clock_gettime(__sanitizer_clockid_t clk_id, void *tp);
+#endif
// Linux-only syscalls.
#if SANITIZER_LINUX
@@ -96,7 +98,6 @@ class ThreadLister {
// Exposed for testing.
uptr ThreadDescriptorSize();
uptr ThreadSelf();
-uptr ThreadSelfOffset();
// Matches a library's file name against a base name (stripping path and version
// information).
diff --git a/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp
index bc10e89b1ed..572aa86fa53 100644
--- a/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp
@@ -36,6 +36,7 @@
#include <link.h>
#include <pthread.h>
#include <signal.h>
+#include <sys/mman.h>
#include <sys/resource.h>
#include <syslog.h>
@@ -48,6 +49,10 @@
#include <osreldate.h>
#include <sys/sysctl.h>
#define pthread_getattr_np pthread_attr_get_np
+// The MAP_NORESERVE define has been removed in FreeBSD 11.x, and even before
+// that, it was never implemented. So just define it to zero.
+#undef MAP_NORESERVE
+#define MAP_NORESERVE 0
#endif
#if SANITIZER_NETBSD
@@ -183,85 +188,35 @@ __attribute__((unused)) static bool GetLibcVersion(int *major, int *minor,
#endif
}
-#if !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_GO && \
- !SANITIZER_NETBSD && !SANITIZER_SOLARIS
-static uptr g_tls_size;
+// True if we can use dlpi_tls_data. glibc before 2.25 may leave NULL (BZ
+// #19826) so dlpi_tls_data cannot be used.
+//
+// musl before 1.2.3 and FreeBSD as of 12.2 incorrectly set dlpi_tls_data to
+// the TLS initialization image
+// https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=254774
+__attribute__((unused)) static int g_use_dlpi_tls_data;
-#ifdef __i386__
-#define CHECK_GET_TLS_STATIC_INFO_VERSION (!__GLIBC_PREREQ(2, 27))
-#else
-#define CHECK_GET_TLS_STATIC_INFO_VERSION 0
-#endif
+#if SANITIZER_GLIBC && !SANITIZER_GO
+__attribute__((unused)) static uptr g_tls_size;
+void InitTlsSize() {
+ int major, minor, patch;
+ g_use_dlpi_tls_data =
+ GetLibcVersion(&major, &minor, &patch) && major == 2 && minor >= 25;
-#if CHECK_GET_TLS_STATIC_INFO_VERSION
-#define DL_INTERNAL_FUNCTION __attribute__((regparm(3), stdcall))
-#else
-#define DL_INTERNAL_FUNCTION
+#if defined(__x86_64__) || defined(__powerpc64__)
+ void *get_tls_static_info = dlsym(RTLD_NEXT, "_dl_get_tls_static_info");
+ size_t tls_align;
+ ((void (*)(size_t *, size_t *))get_tls_static_info)(&g_tls_size, &tls_align);
#endif
-
-namespace {
-struct GetTlsStaticInfoCall {
- typedef void (*get_tls_func)(size_t*, size_t*);
-};
-struct GetTlsStaticInfoRegparmCall {
- typedef void (*get_tls_func)(size_t*, size_t*) DL_INTERNAL_FUNCTION;
-};
-
-template <typename T>
-void CallGetTls(void* ptr, size_t* size, size_t* align) {
- typename T::get_tls_func get_tls;
- CHECK_EQ(sizeof(get_tls), sizeof(ptr));
- internal_memcpy(&get_tls, &ptr, sizeof(ptr));
- CHECK_NE(get_tls, 0);
- get_tls(size, align);
-}
-
-bool CmpLibcVersion(int major, int minor, int patch) {
- int ma;
- int mi;
- int pa;
- if (!GetLibcVersion(&ma, &mi, &pa))
- return false;
- if (ma > major)
- return true;
- if (ma < major)
- return false;
- if (mi > minor)
- return true;
- if (mi < minor)
- return false;
- return pa >= patch;
-}
-
-} // namespace
-
-void InitTlsSize() {
- // all current supported platforms have 16 bytes stack alignment
- const size_t kStackAlign = 16;
- void *get_tls_static_info_ptr = dlsym(RTLD_NEXT, "_dl_get_tls_static_info");
- size_t tls_size = 0;
- size_t tls_align = 0;
- // On i?86, _dl_get_tls_static_info used to be internal_function, i.e.
- // __attribute__((regparm(3), stdcall)) before glibc 2.27 and is normal
- // function in 2.27 and later.
- if (CHECK_GET_TLS_STATIC_INFO_VERSION && !CmpLibcVersion(2, 27, 0))
- CallGetTls<GetTlsStaticInfoRegparmCall>(get_tls_static_info_ptr,
- &tls_size, &tls_align);
- else
- CallGetTls<GetTlsStaticInfoCall>(get_tls_static_info_ptr,
- &tls_size, &tls_align);
- if (tls_align < kStackAlign)
- tls_align = kStackAlign;
- g_tls_size = RoundUpTo(tls_size, tls_align);
}
#else
void InitTlsSize() { }
-#endif
+#endif // SANITIZER_GLIBC && !SANITIZER_GO
-#if (defined(__x86_64__) || defined(__i386__) || defined(__mips__) || \
- defined(__aarch64__) || defined(__powerpc64__) || defined(__s390__) || \
- defined(__arm__) || SANITIZER_RISCV64) && \
- SANITIZER_LINUX && !SANITIZER_ANDROID
+// On glibc x86_64, ThreadDescriptorSize() needs to be precise due to the usage
+// of g_tls_size. On other targets, ThreadDescriptorSize() is only used by lsan
+// to get the pointer to thread-specific data keys in the thread control block.
+#if (SANITIZER_FREEBSD || SANITIZER_LINUX) && !SANITIZER_ANDROID
// sizeof(struct pthread) from glibc.
static atomic_uintptr_t thread_descriptor_size;
@@ -294,9 +249,18 @@ uptr ThreadDescriptorSize() {
val = FIRST_32_SECOND_64(1168, 2288);
else if (minor <= 14)
val = FIRST_32_SECOND_64(1168, 2304);
- else
+ else if (minor < 32) // Unknown version
val = FIRST_32_SECOND_64(1216, 2304);
+ else // minor == 32
+ val = FIRST_32_SECOND_64(1344, 2496);
}
+#elif defined(__s390__) || defined(__sparc__)
+ // The size of a prefix of TCB including pthread::{specific_1stblock,specific}
+ // suffices. Just return offsetof(struct pthread, specific_used), which hasn't
+ // changed since 2007-05. Technically this applies to i386/x86_64 as well but
+ // we call _dl_get_tls_static_info and need the precise size of struct
+ // pthread.
+ return FIRST_32_SECOND_64(524, 1552);
#elif defined(__mips__)
// TODO(sagarthakur): add more values as per different glibc versions.
val = FIRST_32_SECOND_64(1152, 1776);
@@ -320,21 +284,12 @@ uptr ThreadDescriptorSize() {
val = 1776;
#elif defined(__powerpc64__)
val = 1776; // from glibc.ppc64le 2.20-8.fc21
-#elif defined(__s390__)
- val = FIRST_32_SECOND_64(1152, 1776); // valid for glibc 2.22
#endif
if (val)
atomic_store_relaxed(&thread_descriptor_size, val);
return val;
}
-// The offset at which pointer to self is located in the thread descriptor.
-const uptr kThreadSelfOffset = FIRST_32_SECOND_64(8, 16);
-
-uptr ThreadSelfOffset() {
- return kThreadSelfOffset;
-}
-
#if defined(__mips__) || defined(__powerpc64__) || SANITIZER_RISCV64
// TlsPreTcbSize includes size of struct pthread_descr and size of tcb
// head structure. It lies before the static tls blocks.
@@ -353,68 +308,74 @@ static uptr TlsPreTcbSize() {
}
#endif
-uptr ThreadSelf() {
- uptr descr_addr;
-#if defined(__i386__)
- asm("mov %%gs:%c1,%0" : "=r"(descr_addr) : "i"(kThreadSelfOffset));
-#elif defined(__x86_64__)
- asm("mov %%fs:%c1,%0" : "=r"(descr_addr) : "i"(kThreadSelfOffset));
-#elif defined(__mips__)
- // MIPS uses TLS variant I. The thread pointer (in hardware register $29)
- // points to the end of the TCB + 0x7000. The pthread_descr structure is
- // immediately in front of the TCB. TlsPreTcbSize() includes the size of the
- // TCB and the size of pthread_descr.
- const uptr kTlsTcbOffset = 0x7000;
- uptr thread_pointer;
- asm volatile(".set push;\
- .set mips64r2;\
- rdhwr %0,$29;\
- .set pop" : "=r" (thread_pointer));
- descr_addr = thread_pointer - kTlsTcbOffset - TlsPreTcbSize();
-#elif defined(__aarch64__) || defined(__arm__)
- descr_addr = reinterpret_cast<uptr>(__builtin_thread_pointer()) -
- ThreadDescriptorSize();
-#elif SANITIZER_RISCV64
- // https://github.com/riscv/riscv-elf-psabi-doc/issues/53
- uptr thread_pointer = reinterpret_cast<uptr>(__builtin_thread_pointer());
- descr_addr = thread_pointer - TlsPreTcbSize();
-#elif defined(__s390__)
- descr_addr = reinterpret_cast<uptr>(__builtin_thread_pointer());
-#elif defined(__powerpc64__)
- // PPC64LE uses TLS variant I. The thread pointer (in GPR 13)
- // points to the end of the TCB + 0x7000. The pthread_descr structure is
- // immediately in front of the TCB. TlsPreTcbSize() includes the size of the
- // TCB and the size of pthread_descr.
- const uptr kTlsTcbOffset = 0x7000;
- uptr thread_pointer;
- asm("addi %0,13,%1" : "=r"(thread_pointer) : "I"(-kTlsTcbOffset));
- descr_addr = thread_pointer - TlsPreTcbSize();
-#else
-#error "unsupported CPU arch"
-#endif
- return descr_addr;
-}
-#endif // (x86_64 || i386 || MIPS) && SANITIZER_LINUX
+#if !SANITIZER_GO
+namespace {
+struct TlsBlock {
+ uptr begin, end, align;
+ size_t tls_modid;
+ bool operator<(const TlsBlock &rhs) const { return begin < rhs.begin; }
+};
+} // namespace
-#if SANITIZER_FREEBSD
-static void **ThreadSelfSegbase() {
- void **segbase = 0;
-#if defined(__i386__)
- // sysarch(I386_GET_GSBASE, segbase);
- __asm __volatile("mov %%gs:0, %0" : "=r" (segbase));
-#elif defined(__x86_64__)
- // sysarch(AMD64_GET_FSBASE, segbase);
- __asm __volatile("movq %%fs:0, %0" : "=r" (segbase));
-#else
-#error "unsupported CPU arch"
+extern "C" void *__tls_get_addr(size_t *);
+
+static int CollectStaticTlsBlocks(struct dl_phdr_info *info, size_t size,
+ void *data) {
+ if (!info->dlpi_tls_modid)
+ return 0;
+ uptr begin = (uptr)info->dlpi_tls_data;
+#ifndef __s390__
+ if (!g_use_dlpi_tls_data) {
+ // Call __tls_get_addr as a fallback. This forces TLS allocation on glibc
+ // and FreeBSD.
+ size_t mod_and_off[2] = {info->dlpi_tls_modid, 0};
+ begin = (uptr)__tls_get_addr(mod_and_off);
+ }
#endif
- return segbase;
+ for (unsigned i = 0; i != info->dlpi_phnum; ++i)
+ if (info->dlpi_phdr[i].p_type == PT_TLS) {
+ static_cast<InternalMmapVector<TlsBlock> *>(data)->push_back(
+ TlsBlock{begin, begin + info->dlpi_phdr[i].p_memsz,
+ info->dlpi_phdr[i].p_align, info->dlpi_tls_modid});
+ break;
+ }
+ return 0;
}
-uptr ThreadSelf() {
- return (uptr)ThreadSelfSegbase()[2];
-}
-#endif // SANITIZER_FREEBSD
+__attribute__((unused)) static void GetStaticTlsBoundary(uptr *addr, uptr *size,
+ uptr *align) {
+ InternalMmapVector<TlsBlock> ranges;
+ dl_iterate_phdr(CollectStaticTlsBlocks, &ranges);
+ uptr len = ranges.size();
+ Sort(ranges.begin(), len);
+ // Find the range with tls_modid=1. For glibc, because libc.so uses PT_TLS,
+ // this module is guaranteed to exist and is one of the initially loaded
+ // modules.
+ uptr one = 0;
+ while (one != len && ranges[one].tls_modid != 1) ++one;
+ if (one == len) {
+ // This may happen with musl if no module uses PT_TLS.
+ *addr = 0;
+ *size = 0;
+ *align = 1;
+ return;
+ }
+ // Find the maximum consecutive ranges. We consider two modules consecutive if
+ // the gap is smaller than the alignment. The dynamic loader places static TLS
+ // blocks this way not to waste space.
+ uptr l = one;
+ *align = ranges[l].align;
+ while (l != 0 && ranges[l].begin < ranges[l - 1].end + ranges[l - 1].align)
+ *align = Max(*align, ranges[--l].align);
+ uptr r = one + 1;
+ while (r != len && ranges[r].begin < ranges[r - 1].end + ranges[r - 1].align)
+ *align = Max(*align, ranges[r++].align);
+ *addr = ranges[l].begin;
+ *size = ranges[r - 1].end - ranges[l].begin;
+}
+#endif // !SANITIZER_GO
+#endif // (x86_64 || i386 || mips || ...) && (SANITIZER_FREEBSD ||
+ // SANITIZER_LINUX) && !SANITIZER_ANDROID
#if SANITIZER_NETBSD
static struct tls_tcb * ThreadSelfTlsTcb() {
@@ -465,33 +426,67 @@ static void GetTls(uptr *addr, uptr *size) {
*addr = 0;
*size = 0;
}
-#elif SANITIZER_LINUX
-#if defined(__x86_64__) || defined(__i386__) || defined(__s390__)
- *addr = ThreadSelf();
- *size = GetTlsSize();
+#elif SANITIZER_GLIBC && defined(__x86_64__)
+ // For x86-64, use an O(1) approach which requires precise
+ // ThreadDescriptorSize. g_tls_size was initialized in InitTlsSize.
+ asm("mov %%fs:16,%0" : "=r"(*addr));
+ *size = g_tls_size;
*addr -= *size;
*addr += ThreadDescriptorSize();
-#elif defined(__mips__) || defined(__aarch64__) || defined(__powerpc64__) || \
- defined(__arm__) || SANITIZER_RISCV64
- *addr = ThreadSelf();
- *size = GetTlsSize();
+#elif SANITIZER_GLIBC && defined(__powerpc64__)
+ // Workaround for glibc<2.25(?). 2.27 is known to not need this.
+ uptr tp;
+ asm("addi %0,13,-0x7000" : "=r"(tp));
+ const uptr pre_tcb_size = TlsPreTcbSize();
+ *addr = tp - pre_tcb_size;
+ *size = g_tls_size + pre_tcb_size;
+#elif SANITIZER_FREEBSD || SANITIZER_LINUX
+ uptr align;
+ GetStaticTlsBoundary(addr, size, &align);
+#if defined(__x86_64__) || defined(__i386__) || defined(__s390__) || \
+ defined(__sparc__)
+ if (SANITIZER_GLIBC) {
+#if defined(__x86_64__) || defined(__i386__)
+ align = Max<uptr>(align, 64);
#else
- *addr = 0;
- *size = 0;
+ align = Max<uptr>(align, 16);
#endif
-#elif SANITIZER_FREEBSD
- void** segbase = ThreadSelfSegbase();
- *addr = 0;
- *size = 0;
- if (segbase != 0) {
- // tcbalign = 16
- // tls_size = round(tls_static_space, tcbalign);
- // dtv = segbase[1];
- // dtv[2] = segbase - tls_static_space;
- void **dtv = (void**) segbase[1];
- *addr = (uptr) dtv[2];
- *size = (*addr == 0) ? 0 : ((uptr) segbase[0] - (uptr) dtv[2]);
}
+ const uptr tp = RoundUpTo(*addr + *size, align);
+
+ // lsan requires the range to additionally cover the static TLS surplus
+ // (elf/dl-tls.c defines 1664). Otherwise there may be false positives for
+ // allocations only referenced by tls in dynamically loaded modules.
+ if (SANITIZER_GLIBC)
+ *size += 1644;
+ else if (SANITIZER_FREEBSD)
+ *size += 128; // RTLD_STATIC_TLS_EXTRA
+
+ // Extend the range to include the thread control block. On glibc, lsan needs
+ // the range to include pthread::{specific_1stblock,specific} so that
+ // allocations only referenced by pthread_setspecific can be scanned. This may
+ // underestimate by at most TLS_TCB_ALIGN-1 bytes but it should be fine
+ // because the number of bytes after pthread::specific is larger.
+ *addr = tp - RoundUpTo(*size, align);
+ *size = tp - *addr + ThreadDescriptorSize();
+#else
+ if (SANITIZER_GLIBC)
+ *size += 1664;
+ else if (SANITIZER_FREEBSD)
+ *size += 128; // RTLD_STATIC_TLS_EXTRA
+#if defined(__mips__) || defined(__powerpc64__) || SANITIZER_RISCV64
+ const uptr pre_tcb_size = TlsPreTcbSize();
+ *addr -= pre_tcb_size;
+ *size += pre_tcb_size;
+#else
+ // arm and aarch64 reserve two words at TP, so this underestimates the range.
+ // However, this is sufficient for the purpose of finding the pointers to
+ // thread-specific data keys.
+ const uptr tcb_size = ThreadDescriptorSize();
+ *addr -= tcb_size;
+ *size += tcb_size;
+#endif
+#endif
#elif SANITIZER_NETBSD
struct tls_tcb * const tcb = ThreadSelfTlsTcb();
*addr = 0;
@@ -518,15 +513,13 @@ static void GetTls(uptr *addr, uptr *size) {
#if !SANITIZER_GO
uptr GetTlsSize() {
-#if SANITIZER_FREEBSD || SANITIZER_ANDROID || SANITIZER_NETBSD || \
+#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \
SANITIZER_SOLARIS
uptr addr, size;
GetTls(&addr, &size);
return size;
-#elif defined(__mips__) || defined(__powerpc64__) || SANITIZER_RISCV64
- return RoundUpTo(g_tls_size + TlsPreTcbSize(), 16);
#else
- return g_tls_size;
+ return 0;
#endif
}
#endif
@@ -547,10 +540,9 @@ void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
if (!main) {
// If stack and tls intersect, make them non-intersecting.
if (*tls_addr > *stk_addr && *tls_addr < *stk_addr + *stk_size) {
- CHECK_GT(*tls_addr + *tls_size, *stk_addr);
- CHECK_LE(*tls_addr + *tls_size, *stk_addr + *stk_size);
- *stk_size -= *tls_size;
- *tls_addr = *stk_addr + *stk_size;
+ if (*stk_addr + *stk_size < *tls_addr + *tls_size)
+ *tls_size = *stk_addr + *stk_size - *tls_addr;
+ *stk_size = *tls_addr - *stk_addr;
}
}
#endif
@@ -569,20 +561,12 @@ struct DlIteratePhdrData {
bool first;
};
-static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) {
- DlIteratePhdrData *data = (DlIteratePhdrData*)arg;
- InternalScopedString module_name(kMaxPathLength);
- if (data->first) {
- data->first = false;
- // First module is the binary itself.
- ReadBinaryNameCached(module_name.data(), module_name.size());
- } else if (info->dlpi_name) {
- module_name.append("%s", info->dlpi_name);
- }
+static int AddModuleSegments(const char *module_name, dl_phdr_info *info,
+ InternalMmapVectorNoCtor<LoadedModule> *modules) {
if (module_name[0] == '\0')
return 0;
LoadedModule cur_module;
- cur_module.set(module_name.data(), info->dlpi_addr);
+ cur_module.set(module_name, info->dlpi_addr);
for (int i = 0; i < (int)info->dlpi_phnum; i++) {
const Elf_Phdr *phdr = &info->dlpi_phdr[i];
if (phdr->p_type == PT_LOAD) {
@@ -594,7 +578,26 @@ static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) {
writable);
}
}
- data->modules->push_back(cur_module);
+ modules->push_back(cur_module);
+ return 0;
+}
+
+static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) {
+ DlIteratePhdrData *data = (DlIteratePhdrData *)arg;
+ if (data->first) {
+ InternalMmapVector<char> module_name(kMaxPathLength);
+ data->first = false;
+ // First module is the binary itself.
+ ReadBinaryNameCached(module_name.data(), module_name.size());
+ return AddModuleSegments(module_name.data(), info, data->modules);
+ }
+
+ if (info->dlpi_name) {
+ InternalScopedString module_name;
+ module_name.append("%s", info->dlpi_name);
+ return AddModuleSegments(module_name.data(), info, data->modules);
+ }
+
return 0;
}
@@ -729,13 +732,9 @@ u32 GetNumberOfCPUs() {
#elif SANITIZER_SOLARIS
return sysconf(_SC_NPROCESSORS_ONLN);
#else
-#if defined(CPU_COUNT)
cpu_set_t CPUs;
CHECK_EQ(sched_getaffinity(0, sizeof(cpu_set_t), &CPUs), 0);
return CPU_COUNT(&CPUs);
-#else
- return 1;
-#endif
#endif
}
@@ -802,20 +801,13 @@ void LogMessageOnPrintf(const char *str) {
#endif // SANITIZER_LINUX
-#if SANITIZER_LINUX && !SANITIZER_GO
+#if SANITIZER_GLIBC && !SANITIZER_GO
// glibc crashes when using clock_gettime from a preinit_array function as the
// vDSO function pointers haven't been initialized yet. __progname is
// initialized after the vDSO function pointers, so if it exists, is not null
// and is not empty, we can use clock_gettime.
extern "C" SANITIZER_WEAK_ATTRIBUTE char *__progname;
-inline bool CanUseVDSO() {
- // Bionic is safe, it checks for the vDSO function pointers to be initialized.
- if (SANITIZER_ANDROID)
- return true;
- if (&__progname && __progname && *__progname)
- return true;
- return false;
-}
+inline bool CanUseVDSO() { return &__progname && __progname && *__progname; }
// MonotonicNanoTime is a timing function that can leverage the vDSO by calling
// clock_gettime. real_clock_gettime only exists if clock_gettime is
@@ -835,13 +827,13 @@ u64 MonotonicNanoTime() {
return (u64)ts.tv_sec * (1000ULL * 1000 * 1000) + ts.tv_nsec;
}
#else
-// Non-Linux & Go always use the syscall.
+// Non-glibc & Go always use the regular function.
u64 MonotonicNanoTime() {
timespec ts;
- internal_clock_gettime(CLOCK_MONOTONIC, &ts);
+ clock_gettime(CLOCK_MONOTONIC, &ts);
return (u64)ts.tv_sec * (1000ULL * 1000 * 1000) + ts.tv_nsec;
}
-#endif // SANITIZER_LINUX && !SANITIZER_GO
+#endif // SANITIZER_GLIBC && !SANITIZER_GO
void ReExec() {
const char *pathname = "/proc/self/exe";
@@ -910,6 +902,65 @@ uptr MapDynamicShadow(uptr shadow_size_bytes, uptr shadow_scale,
return shadow_start;
}
+static uptr MmapSharedNoReserve(uptr addr, uptr size) {
+ return internal_mmap(
+ reinterpret_cast<void *>(addr), size, PROT_READ | PROT_WRITE,
+ MAP_FIXED | MAP_SHARED | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
+}
+
+static uptr MremapCreateAlias(uptr base_addr, uptr alias_addr,
+ uptr alias_size) {
+#if SANITIZER_LINUX
+ return internal_mremap(reinterpret_cast<void *>(base_addr), 0, alias_size,
+ MREMAP_MAYMOVE | MREMAP_FIXED,
+ reinterpret_cast<void *>(alias_addr));
+#else
+ CHECK(false && "mremap is not supported outside of Linux");
+ return 0;
+#endif
+}
+
+static void CreateAliases(uptr start_addr, uptr alias_size, uptr num_aliases) {
+ uptr total_size = alias_size * num_aliases;
+ uptr mapped = MmapSharedNoReserve(start_addr, total_size);
+ CHECK_EQ(mapped, start_addr);
+
+ for (uptr i = 1; i < num_aliases; ++i) {
+ uptr alias_addr = start_addr + i * alias_size;
+ CHECK_EQ(MremapCreateAlias(start_addr, alias_addr, alias_size), alias_addr);
+ }
+}
+
+uptr MapDynamicShadowAndAliases(uptr shadow_size, uptr alias_size,
+ uptr num_aliases, uptr ring_buffer_size) {
+ CHECK_EQ(alias_size & (alias_size - 1), 0);
+ CHECK_EQ(num_aliases & (num_aliases - 1), 0);
+ CHECK_EQ(ring_buffer_size & (ring_buffer_size - 1), 0);
+
+ const uptr granularity = GetMmapGranularity();
+ shadow_size = RoundUpTo(shadow_size, granularity);
+ CHECK_EQ(shadow_size & (shadow_size - 1), 0);
+
+ const uptr alias_region_size = alias_size * num_aliases;
+ const uptr alignment =
+ 2 * Max(Max(shadow_size, alias_region_size), ring_buffer_size);
+ const uptr left_padding = ring_buffer_size;
+
+ const uptr right_size = alignment;
+ const uptr map_size = left_padding + 2 * alignment;
+
+ const uptr map_start = reinterpret_cast<uptr>(MmapNoAccess(map_size));
+ CHECK_NE(map_start, static_cast<uptr>(-1));
+ const uptr right_start = RoundUpTo(map_start + left_padding, alignment);
+
+ UnmapFromTo(map_start, right_start - left_padding);
+ UnmapFromTo(right_start + right_size, map_start + map_size);
+
+ CreateAliases(right_start + right_size / 2, alias_size, num_aliases);
+
+ return right_start;
+}
+
void InitializePlatformCommonFlags(CommonFlags *cf) {
#if SANITIZER_ANDROID
if (&__libc_get_static_tls_bounds == nullptr)
diff --git a/libsanitizer/sanitizer_common/sanitizer_local_address_space_view.h b/libsanitizer/sanitizer_common/sanitizer_local_address_space_view.h
index 5d1b5264b5e..0e19c4d4a80 100644
--- a/libsanitizer/sanitizer_common/sanitizer_local_address_space_view.h
+++ b/libsanitizer/sanitizer_common/sanitizer_local_address_space_view.h
@@ -7,7 +7,7 @@
//===----------------------------------------------------------------------===//
//
// `LocalAddressSpaceView` provides the local (i.e. target and current address
-// space are the same) implementation of the `AddressSpaveView` interface which
+// space are the same) implementation of the `AddressSpaceView` interface which
// provides a simple interface to load memory from another process (i.e.
// out-of-process)
//
diff --git a/libsanitizer/sanitizer_common/sanitizer_mac.cpp b/libsanitizer/sanitizer_common/sanitizer_mac.cpp
index 011ec6f4a0b..f4c6b442a14 100644
--- a/libsanitizer/sanitizer_common/sanitizer_mac.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_mac.cpp
@@ -37,13 +37,21 @@
extern char **environ;
#endif
-#if defined(__has_include) && __has_include(<os/trace.h>) && defined(__BLOCKS__)
+#if defined(__has_include) && __has_include(<os/trace.h>)
#define SANITIZER_OS_TRACE 1
#include <os/trace.h>
#else
#define SANITIZER_OS_TRACE 0
#endif
+// import new crash reporting api
+#if defined(__has_include) && __has_include(<CrashReporterClient.h>)
+#define HAVE_CRASHREPORTERCLIENT_H 1
+#include <CrashReporterClient.h>
+#else
+#define HAVE_CRASHREPORTERCLIENT_H 0
+#endif
+
#if !SANITIZER_IOS
#include <crt_externs.h> // for _NSGetArgv and _NSGetEnviron
#else
@@ -62,6 +70,7 @@ extern "C" {
#include <mach/mach_time.h>
#include <mach/vm_statistics.h>
#include <malloc/malloc.h>
+#include <os/log.h>
#include <pthread.h>
#include <sched.h>
#include <signal.h>
@@ -133,6 +142,12 @@ uptr internal_munmap(void *addr, uptr length) {
return munmap(addr, length);
}
+uptr internal_mremap(void *old_address, uptr old_size, uptr new_size, int flags,
+ void *new_address) {
+ CHECK(false && "internal_mremap is unimplemented on Mac");
+ return 0;
+}
+
int internal_mprotect(void *addr, uptr length, int prot) {
return mprotect(addr, length, prot);
}
@@ -444,7 +459,7 @@ uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {
// On OS X the executable path is saved to the stack by dyld. Reading it
// from there is much faster than calling dladdr, especially for large
// binaries with symbols.
- InternalScopedString exe_path(kMaxPathLength);
+ InternalMmapVector<char> exe_path(kMaxPathLength);
uint32_t size = exe_path.size();
if (_NSGetExecutablePath(exe_path.data(), &size) == 0 &&
realpath(exe_path.data(), buf) != 0) {
@@ -620,6 +635,23 @@ constexpr u16 GetOSMajorKernelOffset() {
using VersStr = char[64];
+static uptr ApproximateOSVersionViaKernelVersion(VersStr vers) {
+ u16 kernel_major = GetDarwinKernelVersion().major;
+ u16 offset = GetOSMajorKernelOffset();
+ CHECK_GE(kernel_major, offset);
+ u16 os_major = kernel_major - offset;
+
+ const char *format = "%d.0";
+ if (TARGET_OS_OSX) {
+ if (os_major >= 16) { // macOS 11+
+ os_major -= 5;
+ } else { // macOS 10.15 and below
+ format = "10.%d";
+ }
+ }
+ return internal_snprintf(vers, sizeof(VersStr), format, os_major);
+}
+
static void GetOSVersion(VersStr vers) {
uptr len = sizeof(VersStr);
if (SANITIZER_IOSSIM) {
@@ -633,17 +665,19 @@ static void GetOSVersion(VersStr vers) {
} else {
int res =
internal_sysctlbyname("kern.osproductversion", vers, &len, nullptr, 0);
- if (res) {
- // Fallback for XNU 17 (macOS 10.13) and below that do not provide the
- // `kern.osproductversion` property.
- u16 kernel_major = GetDarwinKernelVersion().major;
- u16 offset = GetOSMajorKernelOffset();
- CHECK_LE(kernel_major, 17);
- CHECK_GE(kernel_major, offset);
- u16 os_major = kernel_major - offset;
-
- auto format = TARGET_OS_OSX ? "10.%d" : "%d.0";
- len = internal_snprintf(vers, len, format, os_major);
+
+ // XNU 17 (macOS 10.13) and below do not provide the sysctl
+ // `kern.osproductversion` entry (res != 0).
+ bool no_os_version = res != 0;
+
+ // For launchd, sanitizer initialization runs before sysctl is setup
+ // (res == 0 && len != strlen(vers), vers is not a valid version). However,
+ // the kernel version `kern.osrelease` is available.
+ bool launchd = (res == 0 && internal_strlen(vers) < 3);
+ if (launchd) CHECK_EQ(internal_getpid(), 1);
+
+ if (no_os_version || launchd) {
+ len = ApproximateOSVersionViaKernelVersion(vers);
}
}
CHECK_LT(len, sizeof(VersStr));
@@ -681,7 +715,7 @@ static void MapToMacos(u16 *major, u16 *minor) {
}
static MacosVersion GetMacosAlignedVersionInternal() {
- VersStr vers;
+ VersStr vers = {};
GetOSVersion(vers);
u16 major, minor;
@@ -707,7 +741,7 @@ MacosVersion GetMacosAlignedVersion() {
}
DarwinKernelVersion GetDarwinKernelVersion() {
- VersStr vers;
+ VersStr vers = {};
uptr len = sizeof(VersStr);
int res = internal_sysctlbyname("kern.osrelease", vers, &len, nullptr, 0);
CHECK_EQ(res, 0);
@@ -751,7 +785,51 @@ static BlockingMutex syslog_lock(LINKER_INITIALIZED);
void WriteOneLineToSyslog(const char *s) {
#if !SANITIZER_GO
syslog_lock.CheckLocked();
- asl_log(nullptr, nullptr, ASL_LEVEL_ERR, "%s", s);
+ if (GetMacosAlignedVersion() >= MacosVersion(10, 12)) {
+ os_log_error(OS_LOG_DEFAULT, "%{public}s", s);
+ } else {
+ asl_log(nullptr, nullptr, ASL_LEVEL_ERR, "%s", s);
+ }
+#endif
+}
+
+// buffer to store crash report application information
+static char crashreporter_info_buff[__sanitizer::kErrorMessageBufferSize] = {};
+static BlockingMutex crashreporter_info_mutex(LINKER_INITIALIZED);
+
+extern "C" {
+// Integrate with crash reporter libraries.
+#if HAVE_CRASHREPORTERCLIENT_H
+CRASH_REPORTER_CLIENT_HIDDEN
+struct crashreporter_annotations_t gCRAnnotations
+ __attribute__((section("__DATA," CRASHREPORTER_ANNOTATIONS_SECTION))) = {
+ CRASHREPORTER_ANNOTATIONS_VERSION,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+#if CRASHREPORTER_ANNOTATIONS_VERSION > 4
+ 0,
+#endif
+};
+
+#else
+// fall back to old crashreporter api
+static const char *__crashreporter_info__ __attribute__((__used__)) =
+ &crashreporter_info_buff[0];
+asm(".desc ___crashreporter_info__, 0x10");
+#endif
+
+} // extern "C"
+
+static void CRAppendCrashLogMessage(const char *msg) {
+ BlockingMutexLock l(&crashreporter_info_mutex);
+ internal_strlcat(crashreporter_info_buff, msg,
+ sizeof(crashreporter_info_buff));
+#if HAVE_CRASHREPORTERCLIENT_H
+ (void)CRSetCrashLogMessage(crashreporter_info_buff);
#endif
}
@@ -947,7 +1025,7 @@ void MaybeReexec() {
if (DyldNeedsEnvVariable() && !lib_is_in_env) {
// DYLD_INSERT_LIBRARIES is not set or does not contain the runtime
// library.
- InternalScopedString program_name(1024);
+ InternalMmapVector<char> program_name(1024);
uint32_t buf_size = program_name.size();
_NSGetExecutablePath(program_name.data(), &buf_size);
char *new_env = const_cast<char*>(info.dli_fname);
@@ -1066,7 +1144,7 @@ char **GetArgv() {
return *_NSGetArgv();
}
-#if SANITIZER_IOS
+#if SANITIZER_IOS && !SANITIZER_IOSSIM
// The task_vm_info struct is normally provided by the macOS SDK, but we need
// fields only available in 10.12+. Declare the struct manually to be able to
// build against older SDKs.
@@ -1106,26 +1184,35 @@ static uptr GetTaskInfoMaxAddress() {
uptr GetMaxUserVirtualAddress() {
static uptr max_vm = GetTaskInfoMaxAddress();
- if (max_vm != 0)
- return max_vm - 1;
+ if (max_vm != 0) {
+ const uptr ret_value = max_vm - 1;
+ CHECK_LE(ret_value, SANITIZER_MMAP_RANGE_SIZE);
+ return ret_value;
+ }
// xnu cannot provide vm address limit
# if SANITIZER_WORDSIZE == 32
- return 0xffe00000 - 1;
+ constexpr uptr fallback_max_vm = 0xffe00000 - 1;
# else
- return 0x200000000 - 1;
+ constexpr uptr fallback_max_vm = 0x200000000 - 1;
# endif
+ static_assert(fallback_max_vm <= SANITIZER_MMAP_RANGE_SIZE,
+ "Max virtual address must be less than mmap range size.");
+ return fallback_max_vm;
}
#else // !SANITIZER_IOS
uptr GetMaxUserVirtualAddress() {
# if SANITIZER_WORDSIZE == 64
- return (1ULL << 47) - 1; // 0x00007fffffffffffUL;
+ constexpr uptr max_vm = (1ULL << 47) - 1; // 0x00007fffffffffffUL;
# else // SANITIZER_WORDSIZE == 32
static_assert(SANITIZER_WORDSIZE == 32, "Wrong wordsize");
- return (1ULL << 32) - 1; // 0xffffffff;
+ constexpr uptr max_vm = (1ULL << 32) - 1; // 0xffffffff;
# endif
+ static_assert(max_vm <= SANITIZER_MMAP_RANGE_SIZE,
+ "Max virtual address must be less than mmap range size.");
+ return max_vm;
}
#endif
@@ -1180,6 +1267,12 @@ uptr MapDynamicShadow(uptr shadow_size_bytes, uptr shadow_scale,
return shadow_start;
}
+uptr MapDynamicShadowAndAliases(uptr shadow_size, uptr alias_size,
+ uptr num_aliases, uptr ring_buffer_size) {
+ CHECK(false && "HWASan aliasing is unimplemented on Mac");
+ return 0;
+}
+
uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding,
uptr *largest_gap_found,
uptr *max_occupied_addr) {
diff --git a/libsanitizer/sanitizer_common/sanitizer_mac.h b/libsanitizer/sanitizer_common/sanitizer_mac.h
index a2c42b3bf4f..0b6af5a3c0e 100644
--- a/libsanitizer/sanitizer_common/sanitizer_mac.h
+++ b/libsanitizer/sanitizer_common/sanitizer_mac.h
@@ -14,26 +14,6 @@
#include "sanitizer_common.h"
#include "sanitizer_platform.h"
-
-/* TARGET_OS_OSX is not present in SDKs before Darwin16 (macOS 10.12) use
- TARGET_OS_MAC (we have no support for iOS in any form for these versions,
- so there's no ambiguity). */
-#if !defined(TARGET_OS_OSX) && TARGET_OS_MAC
-# define TARGET_OS_OSX 1
-#endif
-
-/* Other TARGET_OS_xxx are not present on earlier versions, define them to
- 0 (we have no support for them; they are not valid targets anyway). */
-#ifndef TARGET_OS_IOS
-#define TARGET_OS_IOS 0
-#endif
-#ifndef TARGET_OS_TV
-#define TARGET_OS_TV 0
-#endif
-#ifndef TARGET_OS_WATCH
-#define TARGET_OS_WATCH 0
-#endif
-
#if SANITIZER_MAC
#include "sanitizer_posix.h"
@@ -84,22 +64,5 @@ void RestrictMemoryToMaxAddress(uptr max_address);
} // namespace __sanitizer
-extern "C" {
-static char __crashreporter_info_buff__[__sanitizer::kErrorMessageBufferSize] =
- {};
-static const char *__crashreporter_info__ __attribute__((__used__)) =
- &__crashreporter_info_buff__[0];
-asm(".desc ___crashreporter_info__, 0x10");
-} // extern "C"
-
-namespace __sanitizer {
-static BlockingMutex crashreporter_info_mutex(LINKER_INITIALIZED);
-
-inline void CRAppendCrashLogMessage(const char *msg) {
- BlockingMutexLock l(&crashreporter_info_mutex);
- internal_strlcat(__crashreporter_info_buff__, msg,
- sizeof(__crashreporter_info_buff__)); }
-} // namespace __sanitizer
-
#endif // SANITIZER_MAC
#endif // SANITIZER_MAC_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_malloc_mac.inc b/libsanitizer/sanitizer_common/sanitizer_malloc_mac.inc
index 647bcdfe105..e3b664f68b6 100644
--- a/libsanitizer/sanitizer_common/sanitizer_malloc_mac.inc
+++ b/libsanitizer/sanitizer_common/sanitizer_malloc_mac.inc
@@ -120,11 +120,7 @@ INTERCEPTOR(int, malloc_make_nonpurgeable, void *ptr) {
INTERCEPTOR(void, malloc_set_zone_name, malloc_zone_t *zone, const char *name) {
COMMON_MALLOC_ENTER();
- // Allocate |sizeof(COMMON_MALLOC_ZONE_NAME "-") + internal_strlen(name)|
- // bytes.
- size_t buflen =
- sizeof(COMMON_MALLOC_ZONE_NAME "-") + (name ? internal_strlen(name) : 0);
- InternalScopedString new_name(buflen);
+ InternalScopedString new_name;
if (name && zone->introspect == sanitizer_zone.introspect) {
new_name.append(COMMON_MALLOC_ZONE_NAME "-%s", name);
name = new_name.data();
diff --git a/libsanitizer/sanitizer_common/sanitizer_netbsd.cpp b/libsanitizer/sanitizer_common/sanitizer_netbsd.cpp
index 98ac7365da0..ac20f915fef 100644
--- a/libsanitizer/sanitizer_common/sanitizer_netbsd.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_netbsd.cpp
@@ -105,6 +105,12 @@ uptr internal_munmap(void *addr, uptr length) {
return _REAL(munmap, addr, length);
}
+uptr internal_mremap(void *old_address, uptr old_size, uptr new_size, int flags,
+ void *new_address) {
+ CHECK(false && "internal_mremap is unimplemented on NetBSD");
+ return 0;
+}
+
int internal_mprotect(void *addr, uptr length, int prot) {
DEFINE__REAL(int, mprotect, void *a, uptr b, int c);
return _REAL(mprotect, addr, length, prot);
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform.h b/libsanitizer/sanitizer_common/sanitizer_platform.h
index b2372a025c0..2f6458431c8 100644
--- a/libsanitizer/sanitizer_common/sanitizer_platform.h
+++ b/libsanitizer/sanitizer_common/sanitizer_platform.h
@@ -19,12 +19,25 @@
# error "This operating system is not supported"
#endif
+// Get __GLIBC__ on a glibc platform. Exclude Android: features.h includes C
+// function declarations into a .S file which doesn't compile.
+// https://crbug.com/1162741
+#if __has_include(<features.h>) && !defined(__ANDROID__)
+#include <features.h>
+#endif
+
#if defined(__linux__)
# define SANITIZER_LINUX 1
#else
# define SANITIZER_LINUX 0
#endif
+#if defined(__GLIBC__)
+# define SANITIZER_GLIBC 1
+#else
+# define SANITIZER_GLIBC 0
+#endif
+
#if defined(__FreeBSD__)
# define SANITIZER_FREEBSD 1
#else
@@ -46,6 +59,11 @@
#if defined(__APPLE__)
# define SANITIZER_MAC 1
# include <TargetConditionals.h>
+# if TARGET_OS_OSX
+# define SANITIZER_OSX 1
+# else
+# define SANITIZER_OSX 0
+# endif
# if TARGET_OS_IPHONE
# define SANITIZER_IOS 1
# else
@@ -60,6 +78,7 @@
# define SANITIZER_MAC 0
# define SANITIZER_IOS 0
# define SANITIZER_IOSSIM 0
+# define SANITIZER_OSX 0
#endif
#if defined(__APPLE__) && TARGET_OS_IPHONE && TARGET_OS_WATCH
@@ -247,8 +266,12 @@
#define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 38)
#elif defined(__aarch64__)
# if SANITIZER_MAC
-// Darwin iOS/ARM64 has a 36-bit VMA, 64GiB VM
-# define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 36)
+# if SANITIZER_OSX || SANITIZER_IOSSIM
+# define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 47)
+# else
+ // Darwin iOS/ARM64 has a 36-bit VMA, 64GiB VM
+# define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 36)
+# endif
# else
# define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 48)
# endif
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h b/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h
index 18bab346ce6..731df710df5 100644
--- a/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h
+++ b/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h
@@ -46,6 +46,12 @@
#define SI_LINUX_NOT_ANDROID 0
#endif
+#if SANITIZER_GLIBC
+#define SI_GLIBC 1
+#else
+#define SI_GLIBC 0
+#endif
+
#if SANITIZER_ANDROID
#define SI_ANDROID 1
#else
@@ -159,7 +165,7 @@
SANITIZER_INTERCEPT_MEMCMP && \
((SI_POSIX && _GNU_SOURCE) || SI_NETBSD || SI_FREEBSD)
#define SANITIZER_INTERCEPT_STRNDUP SI_POSIX
-#define SANITIZER_INTERCEPT___STRNDUP SI_LINUX_NOT_FREEBSD
+#define SANITIZER_INTERCEPT___STRNDUP SI_GLIBC
#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \
__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070
#define SI_MAC_DEPLOYMENT_BELOW_10_7 1
@@ -183,8 +189,8 @@
#define SANITIZER_INTERCEPT_FPUTS SI_POSIX
#define SANITIZER_INTERCEPT_PUTS SI_POSIX
-#define SANITIZER_INTERCEPT_PREAD64 SI_LINUX_NOT_ANDROID || SI_SOLARIS32
-#define SANITIZER_INTERCEPT_PWRITE64 SI_LINUX_NOT_ANDROID || SI_SOLARIS32
+#define SANITIZER_INTERCEPT_PREAD64 (SI_GLIBC || SI_SOLARIS32)
+#define SANITIZER_INTERCEPT_PWRITE64 (SI_GLIBC || SI_SOLARIS32)
#define SANITIZER_INTERCEPT_READV SI_POSIX
#define SANITIZER_INTERCEPT_WRITEV SI_POSIX
@@ -192,8 +198,8 @@
#define SANITIZER_INTERCEPT_PREADV \
(SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID)
#define SANITIZER_INTERCEPT_PWRITEV SI_LINUX_NOT_ANDROID
-#define SANITIZER_INTERCEPT_PREADV64 SI_LINUX_NOT_ANDROID
-#define SANITIZER_INTERCEPT_PWRITEV64 SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_PREADV64 SI_GLIBC
+#define SANITIZER_INTERCEPT_PWRITEV64 SI_GLIBC
#define SANITIZER_INTERCEPT_PRCTL SI_LINUX
@@ -201,16 +207,16 @@
#define SANITIZER_INTERCEPT_STRPTIME SI_POSIX
#define SANITIZER_INTERCEPT_SCANF SI_POSIX
-#define SANITIZER_INTERCEPT_ISOC99_SCANF SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_ISOC99_SCANF SI_GLIBC
#ifndef SANITIZER_INTERCEPT_PRINTF
#define SANITIZER_INTERCEPT_PRINTF SI_POSIX
#define SANITIZER_INTERCEPT_PRINTF_L (SI_FREEBSD || SI_NETBSD)
-#define SANITIZER_INTERCEPT_ISOC99_PRINTF SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_ISOC99_PRINTF SI_GLIBC
#endif
#define SANITIZER_INTERCEPT___PRINTF_CHK \
- (SANITIZER_INTERCEPT_PRINTF && SI_LINUX_NOT_ANDROID)
+ (SANITIZER_INTERCEPT_PRINTF && SI_GLIBC)
#define SANITIZER_INTERCEPT_FREXP SI_NOT_FUCHSIA
#define SANITIZER_INTERCEPT_FREXPF_FREXPL SI_POSIX
@@ -220,13 +226,11 @@
(SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
#define SANITIZER_INTERCEPT_GETPWENT \
(SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
-#define SANITIZER_INTERCEPT_FGETGRENT_R \
- (SI_FREEBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
+#define SANITIZER_INTERCEPT_FGETGRENT_R (SI_GLIBC || SI_SOLARIS)
#define SANITIZER_INTERCEPT_FGETPWENT SI_LINUX_NOT_ANDROID || SI_SOLARIS
#define SANITIZER_INTERCEPT_GETPWENT_R \
- (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
-#define SANITIZER_INTERCEPT_FGETPWENT_R \
- (SI_FREEBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
+ (SI_FREEBSD || SI_NETBSD || SI_GLIBC || SI_SOLARIS)
+#define SANITIZER_INTERCEPT_FGETPWENT_R (SI_FREEBSD || SI_GLIBC || SI_SOLARIS)
#define SANITIZER_INTERCEPT_SETPWENT \
(SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
#define SANITIZER_INTERCEPT_CLOCK_GETTIME \
@@ -234,8 +238,8 @@
#define SANITIZER_INTERCEPT_CLOCK_GETCPUCLOCKID SI_LINUX
#define SANITIZER_INTERCEPT_GETITIMER SI_POSIX
#define SANITIZER_INTERCEPT_TIME SI_POSIX
-#define SANITIZER_INTERCEPT_GLOB SI_LINUX_NOT_ANDROID || SI_SOLARIS
-#define SANITIZER_INTERCEPT_GLOB64 SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_GLOB (SI_GLIBC || SI_SOLARIS)
+#define SANITIZER_INTERCEPT_GLOB64 SI_GLIBC
#define SANITIZER_INTERCEPT_WAIT SI_POSIX
#define SANITIZER_INTERCEPT_INET SI_POSIX
#define SANITIZER_INTERCEPT_PTHREAD_GETSCHEDPARAM SI_POSIX
@@ -250,8 +254,7 @@
(SI_FREEBSD || SI_LINUX_NOT_ANDROID)
#define SANITIZER_INTERCEPT_GETHOSTBYADDR_R \
(SI_FREEBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
-#define SANITIZER_INTERCEPT_GETHOSTENT_R \
- (SI_FREEBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
+#define SANITIZER_INTERCEPT_GETHOSTENT_R (SI_FREEBSD || SI_GLIBC || SI_SOLARIS)
#define SANITIZER_INTERCEPT_GETSOCKOPT SI_POSIX
#define SANITIZER_INTERCEPT_ACCEPT SI_POSIX
#define SANITIZER_INTERCEPT_ACCEPT4 (SI_LINUX_NOT_ANDROID || SI_NETBSD)
@@ -296,8 +299,7 @@
(SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
#define SANITIZER_INTERCEPT_TCGETATTR SI_LINUX_NOT_ANDROID || SI_SOLARIS
#define SANITIZER_INTERCEPT_REALPATH SI_POSIX
-#define SANITIZER_INTERCEPT_CANONICALIZE_FILE_NAME \
- (SI_LINUX_NOT_ANDROID || SI_SOLARIS)
+#define SANITIZER_INTERCEPT_CANONICALIZE_FILE_NAME (SI_GLIBC || SI_SOLARIS)
#define SANITIZER_INTERCEPT_CONFSTR \
(SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
#define SANITIZER_INTERCEPT_SCHED_GETAFFINITY SI_LINUX_NOT_ANDROID
@@ -324,7 +326,7 @@
#define SANITIZER_INTERCEPT_SIGPROCMASK SI_POSIX
#define SANITIZER_INTERCEPT_PTHREAD_SIGMASK SI_POSIX
#define SANITIZER_INTERCEPT_BACKTRACE \
- (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
+ (SI_FREEBSD || SI_NETBSD || SI_GLIBC || SI_SOLARIS)
#define SANITIZER_INTERCEPT_GETMNTENT SI_LINUX
#define SANITIZER_INTERCEPT_GETMNTENT_R SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_STATFS \
@@ -342,11 +344,11 @@
#define SANITIZER_INTERCEPT_SHMCTL \
(((SI_FREEBSD || SI_LINUX_NOT_ANDROID) && SANITIZER_WORDSIZE == 64) || \
SI_NETBSD || SI_SOLARIS) // NOLINT
-#define SANITIZER_INTERCEPT_RANDOM_R SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_RANDOM_R SI_GLIBC
#define SANITIZER_INTERCEPT_PTHREAD_ATTR_GET SI_POSIX
#define SANITIZER_INTERCEPT_PTHREAD_ATTR_GETINHERITSCHED \
(SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
-#define SANITIZER_INTERCEPT_PTHREAD_ATTR_GETAFFINITY_NP SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_PTHREAD_ATTR_GETAFFINITY_NP SI_GLIBC
#define SANITIZER_INTERCEPT_PTHREAD_ATTR_GET_SCHED SI_POSIX
#define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPSHARED \
(SI_POSIX && !SI_NETBSD)
@@ -360,7 +362,7 @@
#define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETROBUST_NP SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GETPSHARED \
(SI_POSIX && !SI_NETBSD)
-#define SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GETKIND_NP SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GETKIND_NP SI_GLIBC
#define SANITIZER_INTERCEPT_PTHREAD_CONDATTR_GETPSHARED (SI_POSIX && !SI_NETBSD)
#define SANITIZER_INTERCEPT_PTHREAD_CONDATTR_GETCLOCK \
(SI_LINUX_NOT_ANDROID || SI_SOLARIS)
@@ -368,7 +370,7 @@
(SI_LINUX_NOT_ANDROID && !SI_NETBSD)
#define SANITIZER_INTERCEPT_THR_EXIT SI_FREEBSD
#define SANITIZER_INTERCEPT_TMPNAM SI_POSIX
-#define SANITIZER_INTERCEPT_TMPNAM_R SI_LINUX_NOT_ANDROID || SI_SOLARIS
+#define SANITIZER_INTERCEPT_TMPNAM_R (SI_GLIBC || SI_SOLARIS)
#define SANITIZER_INTERCEPT_PTSNAME SI_LINUX
#define SANITIZER_INTERCEPT_PTSNAME_R SI_LINUX
#define SANITIZER_INTERCEPT_TTYNAME SI_POSIX
@@ -381,7 +383,7 @@
#define SANITIZER_INTERCEPT_LGAMMAL (SI_POSIX && !SI_NETBSD)
#define SANITIZER_INTERCEPT_LGAMMA_R (SI_FREEBSD || SI_LINUX || SI_SOLARIS)
#define SANITIZER_INTERCEPT_LGAMMAL_R SI_LINUX_NOT_ANDROID || SI_SOLARIS
-#define SANITIZER_INTERCEPT_DRAND48_R SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_DRAND48_R SI_GLIBC
#define SANITIZER_INTERCEPT_RAND_R \
(SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
#define SANITIZER_INTERCEPT_ICONV \
@@ -396,12 +398,12 @@
(SI_LINUX || SI_FREEBSD || SI_NETBSD || SI_MAC || SI_SOLARIS)
#define SANITIZER_INTERCEPT_PTHREAD_MUTEX SI_POSIX
-#define SANITIZER_INTERCEPT___PTHREAD_MUTEX SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT___PTHREAD_MUTEX SI_GLIBC
#define SANITIZER_INTERCEPT___LIBC_MUTEX SI_NETBSD
#define SANITIZER_INTERCEPT_PTHREAD_SETNAME_NP \
- (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
+ (SI_FREEBSD || SI_NETBSD || SI_GLIBC || SI_SOLARIS)
#define SANITIZER_INTERCEPT_PTHREAD_GETNAME_NP \
- (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
+ (SI_FREEBSD || SI_NETBSD || SI_GLIBC || SI_SOLARIS)
#define SANITIZER_INTERCEPT_TLS_GET_ADDR \
(SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
@@ -419,19 +421,19 @@
#else
#define SANITIZER_INTERCEPT_AEABI_MEM 0
#endif
-#define SANITIZER_INTERCEPT___BZERO SI_MAC || SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT___BZERO SI_MAC || SI_GLIBC
#define SANITIZER_INTERCEPT_BZERO SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_FTIME (!SI_FREEBSD && !SI_NETBSD && SI_POSIX)
-#define SANITIZER_INTERCEPT_XDR SI_LINUX_NOT_ANDROID || SI_SOLARIS
-#define SANITIZER_INTERCEPT_XDRREC SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_XDR (SI_GLIBC || SI_SOLARIS)
+#define SANITIZER_INTERCEPT_XDRREC SI_GLIBC
#define SANITIZER_INTERCEPT_TSEARCH \
(SI_LINUX_NOT_ANDROID || SI_MAC || SI_NETBSD || SI_SOLARIS)
-#define SANITIZER_INTERCEPT_LIBIO_INTERNALS SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_LIBIO_INTERNALS SI_GLIBC
#define SANITIZER_INTERCEPT_FOPEN SI_POSIX
-#define SANITIZER_INTERCEPT_FOPEN64 SI_LINUX_NOT_ANDROID || SI_SOLARIS32
+#define SANITIZER_INTERCEPT_FOPEN64 (SI_GLIBC || SI_SOLARIS32)
#define SANITIZER_INTERCEPT_OPEN_MEMSTREAM \
(SI_LINUX_NOT_ANDROID || SI_NETBSD || SI_SOLARIS)
-#define SANITIZER_INTERCEPT_OBSTACK SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_OBSTACK SI_GLIBC
#define SANITIZER_INTERCEPT_FFLUSH SI_POSIX
#define SANITIZER_INTERCEPT_FCLOSE SI_POSIX
@@ -456,7 +458,7 @@
#define SANITIZER_INTERCEPT_CTERMID_R (SI_MAC || SI_FREEBSD || SI_SOLARIS)
#define SANITIZER_INTERCEPTOR_HOOKS \
- (SI_LINUX || SI_MAC || SI_WINDOWS || SI_NETBSD)
+ (SI_LINUX || SI_MAC || SI_WINDOWS || SI_FREEBSD || SI_NETBSD || SI_SOLARIS)
#define SANITIZER_INTERCEPT_RECV_RECVFROM SI_POSIX
#define SANITIZER_INTERCEPT_SEND_SENDTO SI_POSIX
#define SANITIZER_INTERCEPT_EVENTFD_READ_WRITE SI_LINUX
@@ -479,20 +481,12 @@
#define SANITIZER_INTERCEPT_MMAP SI_POSIX
#define SANITIZER_INTERCEPT_MMAP64 SI_LINUX_NOT_ANDROID
-#define SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO \
- (!SI_FREEBSD && !SI_MAC && !SI_NETBSD && SI_NOT_FUCHSIA && SI_NOT_RTEMS && \
- !SI_SOLARIS) // NOLINT
+#define SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO (SI_GLIBC || SI_ANDROID)
#define SANITIZER_INTERCEPT_MEMALIGN \
(!SI_FREEBSD && !SI_MAC && !SI_NETBSD && SI_NOT_RTEMS)
-#define SANITIZER_INTERCEPT___LIBC_MEMALIGN \
- (!SI_FREEBSD && !SI_MAC && !SI_NETBSD && !SI_OPENBSD && SI_NOT_RTEMS && \
- !SI_ANDROID) // NOLINT
-#define SANITIZER_INTERCEPT_PVALLOC \
- (!SI_FREEBSD && !SI_MAC && !SI_NETBSD && SI_NOT_FUCHSIA && SI_NOT_RTEMS && \
- !SI_SOLARIS) // NOLINT
-#define SANITIZER_INTERCEPT_CFREE \
- (!SI_FREEBSD && !SI_MAC && !SI_NETBSD && SI_NOT_FUCHSIA && SI_NOT_RTEMS && \
- !SI_SOLARIS && !SANITIZER_ANDROID) // NOLINT
+#define SANITIZER_INTERCEPT___LIBC_MEMALIGN SI_GLIBC
+#define SANITIZER_INTERCEPT_PVALLOC (SI_GLIBC || SI_ANDROID)
+#define SANITIZER_INTERCEPT_CFREE (SI_GLIBC && !SANITIZER_RISCV64)
#define SANITIZER_INTERCEPT_REALLOCARRAY SI_POSIX
#define SANITIZER_INTERCEPT_ALIGNED_ALLOC (!SI_MAC && SI_NOT_RTEMS)
#define SANITIZER_INTERCEPT_MALLOC_USABLE_SIZE (!SI_MAC && !SI_NETBSD)
@@ -532,7 +526,7 @@
#define SANITIZER_INTERCEPT_STRMODE (SI_NETBSD || SI_FREEBSD)
#define SANITIZER_INTERCEPT_TTYENT SI_NETBSD
#define SANITIZER_INTERCEPT_PROTOENT (SI_NETBSD || SI_LINUX)
-#define SANITIZER_INTERCEPT_PROTOENT_R (SI_LINUX_NOT_ANDROID)
+#define SANITIZER_INTERCEPT_PROTOENT_R SI_GLIBC
#define SANITIZER_INTERCEPT_NETENT SI_NETBSD
#define SANITIZER_INTERCEPT_SETVBUF \
(SI_NETBSD || SI_FREEBSD || SI_LINUX || SI_MAC)
@@ -583,7 +577,7 @@
#define SANITIZER_INTERCEPT_GETENTROPY SI_FREEBSD
#define SANITIZER_INTERCEPT_QSORT \
(SI_POSIX && !SI_IOSSIM && !SI_WATCHOS && !SI_TVOS && !SI_ANDROID)
-#define SANITIZER_INTERCEPT_QSORT_R (SI_LINUX && !SI_ANDROID)
+#define SANITIZER_INTERCEPT_QSORT_R SI_GLIBC
// sigaltstack on i386 macOS cannot be intercepted due to setjmp()
// calling it and assuming that it does not clobber registers.
#define SANITIZER_INTERCEPT_SIGALTSTACK \
@@ -591,4 +585,25 @@
#define SANITIZER_INTERCEPT_UNAME (SI_POSIX && !SI_FREEBSD)
#define SANITIZER_INTERCEPT___XUNAME SI_FREEBSD
+// This macro gives a way for downstream users to override the above
+// interceptor macros irrespective of the platform they are on. They have
+// to do two things:
+// 1. Build compiler-rt with -DSANITIZER_OVERRIDE_INTERCEPTORS.
+// 2. Provide a header file named sanitizer_intercept_overriders.h in the
+// include path for their compiler-rt build.
+// An example of an overrider for strlen interceptor that one can list in
+// sanitizer_intercept_overriders.h is as follows:
+//
+// #ifdef SANITIZER_INTERCEPT_STRLEN
+// #undef SANITIZER_INTERCEPT_STRLEN
+// #define SANITIZER_INTERCEPT_STRLEN <value of choice>
+// #endif
+//
+// This "feature" is useful for downstream users who do not want some of
+// their libc funtions to be intercepted. They can selectively disable
+// interception of those functions.
+#ifdef SANITIZER_OVERRIDE_INTERCEPTORS
+#include <sanitizer_intercept_overriders.h>
+#endif
+
#endif // #ifndef SANITIZER_PLATFORM_INTERCEPTORS_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.cpp b/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.cpp
index b1c15be58de..b5a45ae72cd 100644
--- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.cpp
@@ -35,7 +35,10 @@
#include <sys/stat.h>
#include <sys/statvfs.h>
#include <sys/time.h>
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-W#warnings"
#include <sys/timeb.h>
+#pragma clang diagnostic pop
#include <sys/times.h>
#include <sys/timespec.h>
#include <sys/types.h>
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cpp b/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cpp
index f22f5039128..c51327e1269 100644
--- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cpp
@@ -26,12 +26,9 @@
// 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. Beware that with <sys/stat.h>, struct stat
-// takes the form of struct stat64 on 32-bit platforms if _FILE_OFFSET_BITS=64.
-// Also, for some platforms (e.g. mips) there are additional members in the
-// <sys/stat.h> struct stat:s.
+// fine with newer headers, too.
#include <linux/posix_types.h>
-#if defined(__x86_64__)
+#if defined(__x86_64__) || defined(__mips__)
#include <sys/stat.h>
#else
#define ino_t __kernel_ino_t
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp
index 1427cec48c4..35a690cba5c 100644
--- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp
@@ -11,18 +11,19 @@
// Sizes and layouts of platform-specific POSIX data structures.
//===----------------------------------------------------------------------===//
-#include "sanitizer_platform.h"
-
-#if SANITIZER_LINUX || SANITIZER_MAC
+#if defined(__linux__) || defined(__APPLE__)
// Tests in this file assume that off_t-dependent data structures match the
// libc ABI. For example, struct dirent here is what readdir() function (as
// exported from libc) returns, and not the user-facing "dirent", which
// depends on _FILE_OFFSET_BITS setting.
// To get this "true" dirent definition, we undefine _FILE_OFFSET_BITS below.
-#ifdef _FILE_OFFSET_BITS
#undef _FILE_OFFSET_BITS
#endif
+// Must go after undef _FILE_OFFSET_BITS.
+#include "sanitizer_platform.h"
+
+#if SANITIZER_LINUX || SANITIZER_MAC
// Must go after undef _FILE_OFFSET_BITS.
#include "sanitizer_glibc_version.h"
@@ -37,6 +38,7 @@
#include <pwd.h>
#include <signal.h>
#include <stddef.h>
+#include <stdio.h>
#include <sys/mman.h>
#include <sys/resource.h>
#include <sys/socket.h>
@@ -58,7 +60,6 @@
#endif
#if !SANITIZER_ANDROID
-#include <fstab.h>
#include <sys/mount.h>
#include <sys/timeb.h>
#include <utmpx.h>
@@ -110,20 +111,31 @@ typedef struct user_fpregs elf_fpregset_t;
#include <wordexp.h>
#endif
-#if SANITIZER_LINUX && !SANITIZER_ANDROID
-#include <glob.h>
-#include <obstack.h>
-#include <mqueue.h>
+#if SANITIZER_LINUX
+#if SANITIZER_GLIBC
+#include <fstab.h>
#include <net/if_ppp.h>
#include <netax25/ax25.h>
#include <netipx/ipx.h>
#include <netrom/netrom.h>
+#include <obstack.h>
#if HAVE_RPC_XDR_H
# include <rpc/xdr.h>
#endif
#include <scsi/scsi.h>
-#include <sys/mtio.h>
+#else
+#include <linux/if_ppp.h>
+#include <linux/kd.h>
+#include <linux/ppp_defs.h>
+#endif // SANITIZER_GLIBC
+
+#if SANITIZER_ANDROID
+#include <linux/mtio.h>
+#else
+#include <glob.h>
+#include <mqueue.h>
#include <sys/kd.h>
+#include <sys/mtio.h>
#include <sys/shm.h>
#include <sys/statvfs.h>
#include <sys/timex.h>
@@ -142,20 +154,14 @@ typedef struct user_fpregs elf_fpregset_t;
#include <sys/msg.h>
#include <sys/ipc.h>
#include <crypt.h>
-#endif // SANITIZER_LINUX && !SANITIZER_ANDROID
+#endif // SANITIZER_ANDROID
-#if SANITIZER_ANDROID
-#include <linux/kd.h>
-#include <linux/mtio.h>
-#include <linux/ppp_defs.h>
-#include <linux/if_ppp.h>
-#endif
-
-#if SANITIZER_LINUX
#include <link.h>
#include <sys/vfs.h>
#include <sys/epoll.h>
#include <linux/capability.h>
+#else
+#include <fstab.h>
#endif // SANITIZER_LINUX
#if SANITIZER_MAC
@@ -202,8 +208,11 @@ namespace __sanitizer {
unsigned struct_statfs64_sz = sizeof(struct statfs64);
#endif // (SANITIZER_MAC && !TARGET_CPU_ARM64) && !SANITIZER_IOS
-#if !SANITIZER_ANDROID
+#if SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_MAC
unsigned struct_fstab_sz = sizeof(struct fstab);
+#endif // SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD ||
+ // SANITIZER_MAC
+#if !SANITIZER_ANDROID
unsigned struct_statfs_sz = sizeof(struct statfs);
unsigned struct_sockaddr_sz = sizeof(struct sockaddr);
unsigned ucontext_t_sz = sizeof(ucontext_t);
@@ -299,7 +308,7 @@ unsigned struct_ElfW_Phdr_sz = sizeof(ElfW(Phdr));
unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
#endif
-#if SANITIZER_LINUX && !SANITIZER_ANDROID
+#if SANITIZER_GLIBC
int glob_nomatch = GLOB_NOMATCH;
int glob_altdirfunc = GLOB_ALTDIRFUNC;
#endif
@@ -422,7 +431,9 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
unsigned struct_input_id_sz = sizeof(struct input_id);
unsigned struct_mtpos_sz = sizeof(struct mtpos);
unsigned struct_rtentry_sz = sizeof(struct rtentry);
+#if SANITIZER_GLIBC || SANITIZER_ANDROID
unsigned struct_termio_sz = sizeof(struct termio);
+#endif
unsigned struct_vt_consize_sz = sizeof(struct vt_consize);
unsigned struct_vt_sizes_sz = sizeof(struct vt_sizes);
unsigned struct_vt_stat_sz = sizeof(struct vt_stat);
@@ -447,7 +458,7 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
unsigned struct_vt_mode_sz = sizeof(struct vt_mode);
#endif // SANITIZER_LINUX
-#if SANITIZER_LINUX && !SANITIZER_ANDROID
+#if SANITIZER_GLIBC
unsigned struct_ax25_parms_struct_sz = sizeof(struct ax25_parms_struct);
unsigned struct_cyclades_monitor_sz = sizeof(struct cyclades_monitor);
#if EV_VERSION > (0x010000)
@@ -470,12 +481,10 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
unsigned struct_sockaddr_ax25_sz = sizeof(struct sockaddr_ax25);
unsigned struct_unimapdesc_sz = sizeof(struct unimapdesc);
unsigned struct_unimapinit_sz = sizeof(struct unimapinit);
-#endif // SANITIZER_LINUX && !SANITIZER_ANDROID
-#if SANITIZER_LINUX && !SANITIZER_ANDROID
unsigned struct_audio_buf_info_sz = sizeof(struct audio_buf_info);
unsigned struct_ppp_stats_sz = sizeof(struct ppp_stats);
-#endif // (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
+#endif // SANITIZER_GLIBC
#if !SANITIZER_ANDROID && !SANITIZER_MAC
unsigned struct_sioc_sg_req_sz = sizeof(struct sioc_sg_req);
@@ -881,6 +890,7 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
unsigned IOCTL_PIO_UNIMAP = PIO_UNIMAP;
unsigned IOCTL_PIO_UNIMAPCLR = PIO_UNIMAPCLR;
unsigned IOCTL_PIO_UNISCRNMAP = PIO_UNISCRNMAP;
+#if SANITIZER_GLIBC
unsigned IOCTL_SCSI_IOCTL_GET_IDLUN = SCSI_IOCTL_GET_IDLUN;
unsigned IOCTL_SCSI_IOCTL_PROBE_HOST = SCSI_IOCTL_PROBE_HOST;
unsigned IOCTL_SCSI_IOCTL_TAGGED_DISABLE = SCSI_IOCTL_TAGGED_DISABLE;
@@ -899,6 +909,7 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
unsigned IOCTL_SIOCNRGETPARMS = SIOCNRGETPARMS;
unsigned IOCTL_SIOCNRRTCTL = SIOCNRRTCTL;
unsigned IOCTL_SIOCNRSETPARMS = SIOCNRSETPARMS;
+#endif
unsigned IOCTL_TIOCGSERIAL = TIOCGSERIAL;
unsigned IOCTL_TIOCSERGETMULTI = TIOCSERGETMULTI;
unsigned IOCTL_TIOCSERSETMULTI = TIOCSERSETMULTI;
@@ -969,7 +980,7 @@ CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phdr);
CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phnum);
#endif // SANITIZER_LINUX || SANITIZER_FREEBSD
-#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
+#if SANITIZER_GLIBC || SANITIZER_FREEBSD
CHECK_TYPE_SIZE(glob_t);
CHECK_SIZE_AND_OFFSET(glob_t, gl_pathc);
CHECK_SIZE_AND_OFFSET(glob_t, gl_pathv);
@@ -980,7 +991,7 @@ CHECK_SIZE_AND_OFFSET(glob_t, gl_readdir);
CHECK_SIZE_AND_OFFSET(glob_t, gl_opendir);
CHECK_SIZE_AND_OFFSET(glob_t, gl_lstat);
CHECK_SIZE_AND_OFFSET(glob_t, gl_stat);
-#endif
+#endif // SANITIZER_GLIBC || SANITIZER_FREEBSD
CHECK_TYPE_SIZE(addrinfo);
CHECK_SIZE_AND_OFFSET(addrinfo, ai_flags);
@@ -1003,17 +1014,27 @@ CHECK_TYPE_SIZE(iovec);
CHECK_SIZE_AND_OFFSET(iovec, iov_base);
CHECK_SIZE_AND_OFFSET(iovec, iov_len);
+// In POSIX, int msg_iovlen; socklen_t msg_controllen; socklen_t cmsg_len; but
+// many implementations don't conform to the standard. Since we pick the
+// non-conforming glibc definition, exclude the checks for musl (incompatible
+// sizes but compatible offsets).
CHECK_TYPE_SIZE(msghdr);
CHECK_SIZE_AND_OFFSET(msghdr, msg_name);
CHECK_SIZE_AND_OFFSET(msghdr, msg_namelen);
CHECK_SIZE_AND_OFFSET(msghdr, msg_iov);
+#if SANITIZER_GLIBC || SANITIZER_ANDROID
CHECK_SIZE_AND_OFFSET(msghdr, msg_iovlen);
+#endif
CHECK_SIZE_AND_OFFSET(msghdr, msg_control);
+#if SANITIZER_GLIBC || SANITIZER_ANDROID
CHECK_SIZE_AND_OFFSET(msghdr, msg_controllen);
+#endif
CHECK_SIZE_AND_OFFSET(msghdr, msg_flags);
CHECK_TYPE_SIZE(cmsghdr);
+#if SANITIZER_GLIBC || SANITIZER_ANDROID
CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_len);
+#endif
CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_level);
CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_type);
@@ -1121,7 +1142,7 @@ CHECK_SIZE_AND_OFFSET(mntent, mnt_passno);
CHECK_TYPE_SIZE(ether_addr);
-#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
+#if SANITIZER_GLIBC || SANITIZER_FREEBSD
CHECK_TYPE_SIZE(ipc_perm);
# if SANITIZER_FREEBSD
CHECK_SIZE_AND_OFFSET(ipc_perm, key);
@@ -1183,7 +1204,7 @@ CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_dstaddr);
CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_data);
#endif
-#if SANITIZER_LINUX
+#if SANITIZER_GLIBC || SANITIZER_ANDROID
COMPILER_CHECK(sizeof(__sanitizer_struct_mallinfo) == sizeof(struct mallinfo));
#endif
@@ -1233,7 +1254,7 @@ COMPILER_CHECK(__sanitizer_XDR_DECODE == XDR_DECODE);
COMPILER_CHECK(__sanitizer_XDR_FREE == XDR_FREE);
#endif
-#if SANITIZER_LINUX && !SANITIZER_ANDROID
+#if SANITIZER_GLIBC
COMPILER_CHECK(sizeof(__sanitizer_FILE) <= sizeof(FILE));
CHECK_SIZE_AND_OFFSET(FILE, _flags);
CHECK_SIZE_AND_OFFSET(FILE, _IO_read_ptr);
@@ -1250,9 +1271,7 @@ CHECK_SIZE_AND_OFFSET(FILE, _IO_save_end);
CHECK_SIZE_AND_OFFSET(FILE, _markers);
CHECK_SIZE_AND_OFFSET(FILE, _chain);
CHECK_SIZE_AND_OFFSET(FILE, _fileno);
-#endif
-#if SANITIZER_LINUX && !SANITIZER_ANDROID
COMPILER_CHECK(sizeof(__sanitizer__obstack_chunk) <= sizeof(_obstack_chunk));
CHECK_SIZE_AND_OFFSET(_obstack_chunk, limit);
CHECK_SIZE_AND_OFFSET(_obstack_chunk, prev);
@@ -1267,7 +1286,7 @@ CHECK_SIZE_AND_OFFSET(cookie_io_functions_t, read);
CHECK_SIZE_AND_OFFSET(cookie_io_functions_t, write);
CHECK_SIZE_AND_OFFSET(cookie_io_functions_t, seek);
CHECK_SIZE_AND_OFFSET(cookie_io_functions_t, close);
-#endif
+#endif // SANITIZER_GLIBC
#if SANITIZER_LINUX || SANITIZER_FREEBSD
CHECK_TYPE_SIZE(sem_t);
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h
index 0812039b038..836b178c131 100644
--- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h
+++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h
@@ -83,7 +83,7 @@ const unsigned struct_kernel_stat64_sz = 104;
#elif defined(__mips__)
const unsigned struct_kernel_stat_sz = SANITIZER_ANDROID
? FIRST_32_SECOND_64(104, 128)
- : FIRST_32_SECOND_64(144, 216);
+ : FIRST_32_SECOND_64(160, 216);
const unsigned struct_kernel_stat64_sz = 104;
#elif defined(__s390__) && !defined(__s390x__)
const unsigned struct_kernel_stat_sz = 64;
@@ -443,6 +443,8 @@ struct __sanitizer_cmsghdr {
int cmsg_type;
};
#else
+// In POSIX, int msg_iovlen; socklen_t msg_controllen; socklen_t cmsg_len; but
+// many implementations don't conform to the standard.
struct __sanitizer_msghdr {
void *msg_name;
unsigned msg_namelen;
diff --git a/libsanitizer/sanitizer_common/sanitizer_posix.cpp b/libsanitizer/sanitizer_common/sanitizer_posix.cpp
index 2e080098283..f8457a6aac4 100644
--- a/libsanitizer/sanitizer_common/sanitizer_posix.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_posix.cpp
@@ -275,8 +275,8 @@ void ReportFile::Write(const char *buffer, uptr length) {
bool GetCodeRangeForFile(const char *module, uptr *start, uptr *end) {
MemoryMappingLayout proc_maps(/*cache_enabled*/false);
- InternalScopedString buff(kMaxPathLength);
- MemoryMappedSegment segment(buff.data(), kMaxPathLength);
+ InternalMmapVector<char> buff(kMaxPathLength);
+ MemoryMappedSegment segment(buff.data(), buff.size());
while (proc_maps.Next(&segment)) {
if (segment.IsExecutable() &&
internal_strcmp(module, segment.filename) == 0) {
diff --git a/libsanitizer/sanitizer_common/sanitizer_posix.h b/libsanitizer/sanitizer_common/sanitizer_posix.h
index e1a2b48e5cd..b65dae64476 100644
--- a/libsanitizer/sanitizer_common/sanitizer_posix.h
+++ b/libsanitizer/sanitizer_common/sanitizer_posix.h
@@ -40,6 +40,10 @@ uptr internal_write(fd_t fd, const void *buf, uptr count);
uptr internal_mmap(void *addr, uptr length, int prot, int flags,
int fd, u64 offset);
uptr internal_munmap(void *addr, uptr length);
+#if SANITIZER_LINUX
+uptr internal_mremap(void *old_address, uptr old_size, uptr new_size, int flags,
+ void *new_address);
+#endif
int internal_mprotect(void *addr, uptr length, int prot);
int internal_madvise(uptr addr, uptr length, int advice);
diff --git a/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp
index 7ff48c35851..d1d8e509c4d 100644
--- a/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp
@@ -143,7 +143,7 @@ void Abort() {
if (GetHandleSignalMode(SIGABRT) != kHandleSignalNo) {
struct sigaction sigact;
internal_memset(&sigact, 0, sizeof(sigact));
- sigact.sa_sigaction = (sa_sigaction_t)SIG_DFL;
+ sigact.sa_handler = SIG_DFL;
internal_sigaction(SIGABRT, &sigact, nullptr);
}
#endif
diff --git a/libsanitizer/sanitizer_common/sanitizer_printf.cpp b/libsanitizer/sanitizer_common/sanitizer_printf.cpp
index a032787114b..5d16dfde678 100644
--- a/libsanitizer/sanitizer_common/sanitizer_printf.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_printf.cpp
@@ -249,26 +249,21 @@ static void NOINLINE SharedPrintfCodeNoBuffer(bool append_pid,
va_list args) {
va_list args2;
va_copy(args2, args);
- const int kLen = 16 * 1024;
- int needed_length;
+ InternalMmapVector<char> v;
+ int needed_length = 0;
char *buffer = local_buffer;
// First try to print a message using a local buffer, and then fall back to
// mmaped buffer.
- for (int use_mmap = 0; use_mmap < 2; use_mmap++) {
+ for (int use_mmap = 0;; use_mmap++) {
if (use_mmap) {
va_end(args);
va_copy(args, args2);
- buffer = (char*)MmapOrDie(kLen, "Report");
- buffer_size = kLen;
+ v.resize(needed_length + 1);
+ buffer_size = v.capacity();
+ v.resize(buffer_size);
+ buffer = &v[0];
}
needed_length = 0;
- // Check that data fits into the current buffer.
-# define CHECK_NEEDED_LENGTH \
- if (needed_length >= buffer_size) { \
- if (!use_mmap) continue; \
- RAW_CHECK_MSG(needed_length < kLen, \
- "Buffer in Report is too short!\n"); \
- }
// Fuchsia's logging infrastructure always keeps track of the logging
// process, thread, and timestamp, so never prepend such information.
if (!SANITIZER_FUCHSIA && append_pid) {
@@ -277,18 +272,20 @@ static void NOINLINE SharedPrintfCodeNoBuffer(bool append_pid,
if (common_flags()->log_exe_name && exe_name) {
needed_length += internal_snprintf(buffer, buffer_size,
"==%s", exe_name);
- CHECK_NEEDED_LENGTH
+ if (needed_length >= buffer_size)
+ continue;
}
needed_length += internal_snprintf(
buffer + needed_length, buffer_size - needed_length, "==%d==", pid);
- CHECK_NEEDED_LENGTH
+ if (needed_length >= buffer_size)
+ continue;
}
needed_length += VSNPrintf(buffer + needed_length,
buffer_size - needed_length, format, args);
- CHECK_NEEDED_LENGTH
+ if (needed_length >= buffer_size)
+ continue;
// If the message fit into the buffer, print it and exit.
break;
-# undef CHECK_NEEDED_LENGTH
}
RawWrite(buffer);
@@ -297,9 +294,6 @@ static void NOINLINE SharedPrintfCodeNoBuffer(bool append_pid,
CallPrintfAndReportCallback(buffer);
LogMessageOnPrintf(buffer);
- // If we had mapped any memory, clean up.
- if (buffer != local_buffer)
- UnmapOrDie((void *)buffer, buffer_size);
va_end(args2);
}
@@ -346,13 +340,24 @@ int internal_snprintf(char *buffer, uptr length, const char *format, ...) {
FORMAT(2, 3)
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_);
- CHECK_LT(length_, size());
+ uptr prev_len = length();
+
+ while (true) {
+ buffer_.resize(buffer_.capacity());
+
+ va_list args;
+ va_start(args, format);
+ uptr sz = VSNPrintf(buffer_.data() + prev_len, buffer_.size() - prev_len,
+ format, args);
+ va_end(args);
+ if (sz < buffer_.size() - prev_len) {
+ buffer_.resize(prev_len + sz + 1);
+ break;
+ }
+
+ buffer_.reserve(buffer_.capacity() * 2);
+ }
+ CHECK_EQ(buffer_[length()], '\0');
}
} // namespace __sanitizer
diff --git a/libsanitizer/sanitizer_common/sanitizer_procmaps_common.cpp b/libsanitizer/sanitizer_common/sanitizer_procmaps_common.cpp
index f2cfcffaf47..1b7dd46d8de 100644
--- a/libsanitizer/sanitizer_common/sanitizer_procmaps_common.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_procmaps_common.cpp
@@ -120,7 +120,7 @@ void MemoryMappingLayout::LoadFromCache() {
void MemoryMappingLayout::DumpListOfModules(
InternalMmapVectorNoCtor<LoadedModule> *modules) {
Reset();
- InternalScopedString module_name(kMaxPathLength);
+ InternalMmapVector<char> module_name(kMaxPathLength);
MemoryMappedSegment segment(module_name.data(), module_name.size());
for (uptr i = 0; Next(&segment); i++) {
const char *cur_name = segment.filename;
diff --git a/libsanitizer/sanitizer_common/sanitizer_procmaps_mac.cpp b/libsanitizer/sanitizer_common/sanitizer_procmaps_mac.cpp
index d02afcfe87a..1f53e3e46d8 100644
--- a/libsanitizer/sanitizer_common/sanitizer_procmaps_mac.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_procmaps_mac.cpp
@@ -354,8 +354,8 @@ bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) {
void MemoryMappingLayout::DumpListOfModules(
InternalMmapVectorNoCtor<LoadedModule> *modules) {
Reset();
- InternalScopedString module_name(kMaxPathLength);
- MemoryMappedSegment segment(module_name.data(), kMaxPathLength);
+ InternalMmapVector<char> module_name(kMaxPathLength);
+ MemoryMappedSegment segment(module_name.data(), module_name.size());
MemoryMappedSegmentData data;
segment.data_ = &data;
while (Next(&segment)) {
diff --git a/libsanitizer/sanitizer_common/sanitizer_procmaps_solaris.cpp b/libsanitizer/sanitizer_common/sanitizer_procmaps_solaris.cpp
index 4063ec8deaa..bf813f235bb 100644
--- a/libsanitizer/sanitizer_common/sanitizer_procmaps_solaris.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_procmaps_solaris.cpp
@@ -9,13 +9,13 @@
// Information about the process mappings (Solaris-specific parts).
//===----------------------------------------------------------------------===//
+// Before Solaris 11.4, <procfs.h> doesn't work in a largefile environment.
+#undef _FILE_OFFSET_BITS
#include "sanitizer_platform.h"
#if SANITIZER_SOLARIS
#include "sanitizer_common.h"
#include "sanitizer_procmaps.h"
-// Before Solaris 11.4, <procfs.h> doesn't work in a largefile environment.
-#undef _FILE_OFFSET_BITS
#include <procfs.h>
#include <limits.h>
diff --git a/libsanitizer/sanitizer_common/sanitizer_ptrauth.h b/libsanitizer/sanitizer_common/sanitizer_ptrauth.h
index a288068bf94..52003546948 100644
--- a/libsanitizer/sanitizer_common/sanitizer_ptrauth.h
+++ b/libsanitizer/sanitizer_common/sanitizer_ptrauth.h
@@ -11,6 +11,24 @@
#if __has_feature(ptrauth_calls)
#include <ptrauth.h>
+#elif defined(__ARM_FEATURE_PAC_DEFAULT) && !defined(__APPLE__)
+inline unsigned long ptrauth_strip(void* __value, unsigned int __key) {
+ // On the stack the link register is protected with Pointer
+ // Authentication Code when compiled with -mbranch-protection.
+ // Let's stripping the PAC unconditionally because xpaclri is in
+ // the NOP space so will do nothing when it is not enabled or not available.
+ unsigned long ret;
+ asm volatile(
+ "mov x30, %1\n\t"
+ "hint #7\n\t" // xpaclri
+ "mov %0, x30\n\t"
+ : "=r"(ret)
+ : "r"(__value)
+ : "x30");
+ return ret;
+}
+#define ptrauth_auth_data(__value, __old_key, __old_data) __value
+#define ptrauth_string_discriminator(__string) ((int)0)
#else
// Copied from <ptrauth.h>
#define ptrauth_strip(__value, __key) __value
@@ -18,6 +36,6 @@
#define ptrauth_string_discriminator(__string) ((int)0)
#endif
-#define STRIP_PC(pc) ((uptr)ptrauth_strip(pc, 0))
+#define STRIP_PAC_PC(pc) ((uptr)ptrauth_strip(pc, 0))
#endif // SANITIZER_PTRAUTH_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_stackdepot.cpp b/libsanitizer/sanitizer_common/sanitizer_stackdepot.cpp
index 4692f50d323..44a95214e38 100644
--- a/libsanitizer/sanitizer_common/sanitizer_stackdepot.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_stackdepot.cpp
@@ -145,8 +145,7 @@ StackTrace StackDepotReverseMap::Get(u32 id) {
if (!map_.size())
return StackTrace();
IdDescPair pair = {id, nullptr};
- uptr idx =
- InternalLowerBound(map_, 0, map_.size(), pair, IdDescPair::IdComparator);
+ uptr idx = InternalLowerBound(map_, pair, IdDescPair::IdComparator);
if (idx > map_.size() || map_[idx].id != id)
return StackTrace();
return map_[idx].desc->load();
diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp b/libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp
index b28fc1cf736..07e4409f4a5 100644
--- a/libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp
@@ -15,6 +15,7 @@
#include "sanitizer_common.h"
#include "sanitizer_flags.h"
#include "sanitizer_platform.h"
+#include "sanitizer_ptrauth.h"
namespace __sanitizer {
@@ -84,8 +85,8 @@ static inline uhwptr *GetCanonicFrame(uptr bp,
// Nope, this does not look right either. This means the frame after next does
// not have a valid frame pointer, but we can still extract the caller PC.
// Unfortunately, there is no way to decide between GCC and LLVM frame
- // layouts. Assume GCC.
- return bp_prev - 1;
+ // layouts. Assume LLVM.
+ return bp_prev;
#else
return (uhwptr*)bp;
#endif
@@ -108,28 +109,21 @@ void BufferedStackTrace::UnwindFast(uptr pc, uptr bp, uptr stack_top,
IsAligned((uptr)frame, sizeof(*frame)) &&
size < max_depth) {
#ifdef __powerpc__
- // PowerPC ABIs specify that the return address is saved on the
- // *caller's* stack frame. Thus we must dereference the back chain
- // to find the caller frame before extracting it.
+ // PowerPC ABIs specify that the return address is saved at offset
+ // 16 of the *caller's* stack frame. Thus we must dereference the
+ // back chain to find the caller frame before extracting it.
uhwptr *caller_frame = (uhwptr*)frame[0];
if (!IsValidFrame((uptr)caller_frame, stack_top, bottom) ||
!IsAligned((uptr)caller_frame, sizeof(uhwptr)))
break;
- // For most ABIs the offset where the return address is saved is two
- // register sizes. The exception is the SVR4 ABI, which uses an
- // offset of only one register size.
-#ifdef _CALL_SYSV
- uhwptr pc1 = caller_frame[1];
-#else
uhwptr pc1 = caller_frame[2];
-#endif
#elif defined(__s390__)
uhwptr pc1 = frame[14];
#elif defined(__riscv)
// frame[-1] contains the return address
uhwptr pc1 = frame[-1];
#else
- uhwptr pc1 = frame[1];
+ uhwptr pc1 = STRIP_PAC_PC((void *)frame[1]);
#endif
// Let's assume that any pointer in the 0th page (i.e. <0x1000 on i386 and
// x86_64) is invalid and stop unwinding here. If we're adding support for
diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace.h b/libsanitizer/sanitizer_common/sanitizer_stacktrace.h
index 0350fe84b04..15616f899d0 100644
--- a/libsanitizer/sanitizer_common/sanitizer_stacktrace.h
+++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace.h
@@ -67,8 +67,6 @@ struct StackTrace {
static uptr GetCurrentPc();
static inline uptr GetPreviousInstructionPc(uptr pc);
static uptr GetNextInstructionPc(uptr pc);
- typedef bool (*SymbolizeCallback)(const void *pc, char *out_buffer,
- int out_size);
};
// Performance-critical, must be in the header.
diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_stacktrace_libcdep.cpp
index 7808ba9b0f5..738633209f0 100644
--- a/libsanitizer/sanitizer_common/sanitizer_stacktrace_libcdep.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace_libcdep.cpp
@@ -23,8 +23,8 @@ void StackTrace::Print() const {
Printf(" <empty stack>\n\n");
return;
}
- InternalScopedString frame_desc(GetPageSizeCached() * 2);
- InternalScopedString dedup_token(GetPageSizeCached());
+ InternalScopedString frame_desc;
+ InternalScopedString dedup_token;
int dedup_frames = common_flags()->dedup_token_length;
bool symbolize = RenderNeedsSymbolization(common_flags()->stack_trace_format);
uptr frame_num = 0;
@@ -125,7 +125,7 @@ void __sanitizer_symbolize_pc(uptr pc, const char *fmt, char *out_buf,
out_buf[out_buf_size - 1] = 0;
return;
}
- InternalScopedString frame_desc(GetPageSizeCached());
+ InternalScopedString frame_desc;
uptr frame_num = 0;
// Reserve one byte for the final 0.
char *out_end = out_buf + out_buf_size - 1;
@@ -156,7 +156,7 @@ void __sanitizer_symbolize_global(uptr data_addr, const char *fmt,
out_buf[0] = 0;
DataInfo DI;
if (!Symbolizer::GetOrInit()->SymbolizeData(data_addr, &DI)) return;
- InternalScopedString data_desc(GetPageSizeCached());
+ InternalScopedString data_desc;
RenderData(&data_desc, fmt, &DI, common_flags()->strip_path_prefix);
internal_strncpy(out_buf, data_desc.data(), out_buf_size);
out_buf[out_buf_size - 1] = 0;
diff --git a/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp
index 0f1cadfeae3..53cfddcfbe0 100644
--- a/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp
@@ -490,6 +490,9 @@ typedef user_regs_struct regs_struct;
#ifndef NT_X86_XSTATE
#define NT_X86_XSTATE 0x202
#endif
+#ifndef PTRACE_GETREGSET
+#define PTRACE_GETREGSET 0x4204
+#endif
// Compiler may use FP registers to store pointers.
static constexpr uptr kExtraRegs[] = {NT_X86_XSTATE, NT_FPREGSET};
@@ -513,6 +516,8 @@ static constexpr uptr kExtraRegs[] = {0};
#elif SANITIZER_RISCV64
typedef struct user_regs_struct regs_struct;
+// sys/ucontext.h already defines REG_SP as 2. Undefine it first.
+#undef REG_SP
#define REG_SP sp
static constexpr uptr kExtraRegs[] = {0};
#define ARCH_IOVEC_FOR_GETREGSET
diff --git a/libsanitizer/sanitizer_common/sanitizer_suppressions.cpp b/libsanitizer/sanitizer_common/sanitizer_suppressions.cpp
index 44c83a66c5f..a674034b8e2 100644
--- a/libsanitizer/sanitizer_common/sanitizer_suppressions.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_suppressions.cpp
@@ -34,7 +34,7 @@ SuppressionContext::SuppressionContext(const char *suppression_types[],
static bool GetPathAssumingFileIsRelativeToExec(const char *file_path,
/*out*/char *new_file_path,
uptr new_file_path_size) {
- InternalScopedString exec(kMaxPathLength);
+ InternalMmapVector<char> exec(kMaxPathLength);
if (ReadBinaryNameCached(exec.data(), exec.size())) {
const char *file_name_pos = StripModuleName(exec.data());
uptr path_to_exec_len = file_name_pos - exec.data();
@@ -69,7 +69,7 @@ void SuppressionContext::ParseFromFile(const char *filename) {
if (filename[0] == '\0')
return;
- InternalScopedString new_file_path(kMaxPathLength);
+ InternalMmapVector<char> new_file_path(kMaxPathLength);
filename = FindFile(filename, new_file_path.data(), new_file_path.size());
// Read the file.
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cpp
index 710da4c1cec..98418b426c3 100644
--- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cpp
@@ -356,7 +356,7 @@ void ParseSymbolizePCOutput(const char *str, SymbolizedStack *res) {
InternalFree(info->function);
info->function = 0;
}
- if (0 == internal_strcmp(info->file, "??")) {
+ if (info->file && 0 == internal_strcmp(info->file, "??")) {
InternalFree(info->file);
info->file = 0;
}
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_markup.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_markup.cpp
index 30cba08ed53..01edef9c1aa 100644
--- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_markup.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_markup.cpp
@@ -54,6 +54,10 @@ bool Symbolizer::GetModuleNameAndOffsetForPC(uptr pc, const char **module_name,
return false;
}
+// This is mainly used by hwasan for online symbolization. This isn't needed
+// since hwasan can always just dump stack frames for offline symbolization.
+bool Symbolizer::SymbolizeFrame(uptr addr, FrameInfo *info) { return false; }
+
// This is used in some places for suppression checking, which we
// don't really support for Fuchsia. It's also used in UBSan to
// identify a PC location to a function name, so we always fill in
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp
index 4dd5cc3ad7c..4cd4b4636f0 100644
--- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp
@@ -400,11 +400,20 @@ const char *Symbolizer::PlatformDemangle(const char *name) {
static SymbolizerTool *ChooseExternalSymbolizer(LowLevelAllocator *allocator) {
const char *path = common_flags()->external_symbolizer_path;
+
+ if (path && internal_strchr(path, '%')) {
+ char *new_path = (char *)InternalAlloc(kMaxPathLength);
+ SubstituteForFlagValue(path, new_path, kMaxPathLength);
+ path = new_path;
+ }
+
const char *binary_name = path ? StripModuleName(path) : "";
+ static const char kLLVMSymbolizerPrefix[] = "llvm-symbolizer";
if (path && path[0] == '\0') {
VReport(2, "External symbolizer is explicitly disabled.\n");
return nullptr;
- } else if (!internal_strcmp(binary_name, "llvm-symbolizer")) {
+ } else if (!internal_strncmp(binary_name, kLLVMSymbolizerPrefix,
+ internal_strlen(kLLVMSymbolizerPrefix))) {
VReport(2, "Using llvm-symbolizer at user-specified path: %s\n", path);
return new(*allocator) LLVMSymbolizer(path, allocator);
} else if (!internal_strcmp(binary_name, "atos")) {
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_report.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_report.cpp
index 06301b83ea1..9287993e665 100644
--- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_report.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_report.cpp
@@ -31,7 +31,7 @@ namespace __sanitizer {
void ReportErrorSummary(const char *error_type, const AddressInfo &info,
const char *alt_tool_name) {
if (!common_flags()->print_summary) return;
- InternalScopedString buff(kMaxSummaryLength);
+ InternalScopedString buff;
buff.append("%s ", error_type);
RenderFrame(&buff, "%L %F", 0, info.address, &info,
common_flags()->symbolize_vs_style,
@@ -150,7 +150,7 @@ static void PrintMemoryByte(InternalScopedString *str, const char *before,
static void MaybeDumpInstructionBytes(uptr pc) {
if (!common_flags()->dump_instruction_bytes || (pc < GetPageSizeCached()))
return;
- InternalScopedString str(1024);
+ InternalScopedString str;
str.append("First 16 instruction bytes at pc: ");
if (IsAccessibleMemoryRange(pc, 16)) {
for (int i = 0; i < 16; ++i) {
@@ -211,7 +211,7 @@ static void ReportDeadlySignalImpl(const SignalContext &sig, u32 tid,
Report("The signal is caused by a %s memory access.\n", access_type);
if (!sig.is_true_faulting_addr)
Report("Hint: this fault was caused by a dereference of a high value "
- "address (see register values below). Dissassemble the provided "
+ "address (see register values below). Disassemble the provided "
"pc to learn which register was used.\n");
else if (sig.addr < GetPageSizeCached())
Report("Hint: address points to the zero page.\n");
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cpp
index 48fa2d1033a..702d901353d 100644
--- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cpp
@@ -136,9 +136,10 @@ void InitializeDbgHelpIfNeeded() {
bool WinSymbolizerTool::SymbolizePC(uptr addr, SymbolizedStack *frame) {
InitializeDbgHelpIfNeeded();
- // See http://msdn.microsoft.com/en-us/library/ms680578(VS.85).aspx
- char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(CHAR)];
- PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer;
+ // See https://docs.microsoft.com/en-us/windows/win32/debug/retrieving-symbol-information-by-address
+ InternalMmapVector<char> buffer(sizeof(SYMBOL_INFO) +
+ MAX_SYM_NAME * sizeof(CHAR));
+ PSYMBOL_INFO symbol = (PSYMBOL_INFO)&buffer[0];
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
symbol->MaxNameLen = MAX_SYM_NAME;
DWORD64 offset = 0;
@@ -223,7 +224,7 @@ bool SymbolizerProcess::StartSymbolizerSubprocess() {
// Compute the command line. Wrap double quotes around everything.
const char *argv[kArgVMax];
GetArgV(path_, argv);
- InternalScopedString command_line(kMaxPathLength * 3);
+ InternalScopedString command_line;
for (int i = 0; argv[i]; i++) {
const char *arg = argv[i];
int arglen = internal_strlen(arg);
@@ -281,8 +282,15 @@ static void ChooseSymbolizerTools(IntrusiveList<SymbolizerTool> *list,
return;
}
- // Add llvm-symbolizer in case the binary has dwarf.
+ // Add llvm-symbolizer.
const char *user_path = common_flags()->external_symbolizer_path;
+
+ if (user_path && internal_strchr(user_path, '%')) {
+ char *new_path = (char *)InternalAlloc(kMaxPathLength);
+ SubstituteForFlagValue(user_path, new_path, kMaxPathLength);
+ user_path = new_path;
+ }
+
const char *path =
user_path ? user_path : FindPathToBinary("llvm-symbolizer.exe");
if (path) {
diff --git a/libsanitizer/sanitizer_common/sanitizer_termination.cpp b/libsanitizer/sanitizer_common/sanitizer_termination.cpp
index 84be6fc3234..6a54734353c 100644
--- a/libsanitizer/sanitizer_common/sanitizer_termination.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_termination.cpp
@@ -59,26 +59,31 @@ void NORETURN Die() {
internal__exit(common_flags()->exitcode);
}
-static CheckFailedCallbackType CheckFailedCallback;
-void SetCheckFailedCallback(CheckFailedCallbackType callback) {
- CheckFailedCallback = callback;
+static void (*CheckUnwindCallback)();
+void SetCheckUnwindCallback(void (*callback)()) {
+ CheckUnwindCallback = callback;
}
-const int kSecondsToSleepWhenRecursiveCheckFailed = 2;
-
void NORETURN CheckFailed(const char *file, int line, const char *cond,
u64 v1, u64 v2) {
- static atomic_uint32_t num_calls;
- if (atomic_fetch_add(&num_calls, 1, memory_order_relaxed) > 10) {
- SleepForSeconds(kSecondsToSleepWhenRecursiveCheckFailed);
+ u32 tid = GetTid();
+ Printf("%s: CHECK failed: %s:%d \"%s\" (0x%zx, 0x%zx) (tid=%u)\n",
+ SanitizerToolName, StripModuleName(file), line, cond, (uptr)v1,
+ (uptr)v2, tid);
+ static atomic_uint32_t first_tid;
+ u32 cmp = 0;
+ if (!atomic_compare_exchange_strong(&first_tid, &cmp, tid,
+ memory_order_relaxed)) {
+ if (cmp == tid) {
+ // Recursing into CheckFailed.
+ } else {
+ // Another thread fails already, let it print the stack and terminate.
+ SleepForSeconds(2);
+ }
Trap();
}
-
- if (CheckFailedCallback) {
- CheckFailedCallback(file, line, cond, v1, v2);
- }
- Report("Sanitizer CHECK failed: %s:%d %s (%lld, %lld)\n", file, line, cond,
- v1, v2);
+ if (CheckUnwindCallback)
+ CheckUnwindCallback();
Die();
}
diff --git a/libsanitizer/sanitizer_common/sanitizer_thread_registry.cpp b/libsanitizer/sanitizer_common/sanitizer_thread_registry.cpp
index f2c6f279931..3273da38bfd 100644
--- a/libsanitizer/sanitizer_common/sanitizer_thread_registry.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_thread_registry.cpp
@@ -85,7 +85,7 @@ void ThreadContextBase::SetCreated(uptr _user_id, u64 _unique_id,
unique_id = _unique_id;
detached = _detached;
// Parent tid makes no sense for the main thread.
- if (tid != 0)
+ if (tid != kMainTid)
parent_tid = _parent_tid;
OnCreated(arg);
}
@@ -99,8 +99,6 @@ void ThreadContextBase::Reset() {
// ThreadRegistry implementation.
-const u32 ThreadRegistry::kUnknownTid = ~0U;
-
ThreadRegistry::ThreadRegistry(ThreadContextFactory factory, u32 max_threads,
u32 thread_quarantine_size, u32 max_reuse)
: context_factory_(factory),
@@ -135,7 +133,7 @@ uptr ThreadRegistry::GetMaxAliveThreads() {
u32 ThreadRegistry::CreateThread(uptr user_id, bool detached, u32 parent_tid,
void *arg) {
BlockingMutexLock l(&mtx_);
- u32 tid = kUnknownTid;
+ u32 tid = kInvalidTid;
ThreadContextBase *tctx = QuarantinePop();
if (tctx) {
tid = tctx->tid;
@@ -155,7 +153,7 @@ u32 ThreadRegistry::CreateThread(uptr user_id, bool detached, u32 parent_tid,
Die();
}
CHECK_NE(tctx, 0);
- CHECK_NE(tid, kUnknownTid);
+ CHECK_NE(tid, kInvalidTid);
CHECK_LT(tid, max_threads_);
CHECK_EQ(tctx->status, ThreadStatusInvalid);
alive_threads_++;
@@ -186,7 +184,7 @@ u32 ThreadRegistry::FindThread(FindThreadCallback cb, void *arg) {
if (tctx != 0 && cb(tctx, arg))
return tctx->tid;
}
- return kUnknownTid;
+ return kInvalidTid;
}
ThreadContextBase *
@@ -278,7 +276,7 @@ void ThreadRegistry::JoinThread(u32 tid, void *arg) {
// really started. We just did CreateThread for a prospective new
// thread before trying to create it, and then failed to actually
// create it, and so never called StartThread.
-void ThreadRegistry::FinishThread(u32 tid) {
+ThreadStatus ThreadRegistry::FinishThread(u32 tid) {
BlockingMutexLock l(&mtx_);
CHECK_GT(alive_threads_, 0);
alive_threads_--;
@@ -286,6 +284,7 @@ void ThreadRegistry::FinishThread(u32 tid) {
ThreadContextBase *tctx = threads_[tid];
CHECK_NE(tctx, 0);
bool dead = tctx->detached;
+ ThreadStatus prev_status = tctx->status;
if (tctx->status == ThreadStatusRunning) {
CHECK_GT(running_threads_, 0);
running_threads_--;
@@ -300,6 +299,7 @@ void ThreadRegistry::FinishThread(u32 tid) {
QuarantinePush(tctx);
}
tctx->SetDestroyed();
+ return prev_status;
}
void ThreadRegistry::StartThread(u32 tid, tid_t os_id, ThreadType thread_type,
diff --git a/libsanitizer/sanitizer_common/sanitizer_thread_registry.h b/libsanitizer/sanitizer_common/sanitizer_thread_registry.h
index 85c522a31ca..dcd445c28ae 100644
--- a/libsanitizer/sanitizer_common/sanitizer_thread_registry.h
+++ b/libsanitizer/sanitizer_common/sanitizer_thread_registry.h
@@ -87,8 +87,6 @@ typedef ThreadContextBase* (*ThreadContextFactory)(u32 tid);
class ThreadRegistry {
public:
- static const u32 kUnknownTid;
-
ThreadRegistry(ThreadContextFactory factory, u32 max_threads,
u32 thread_quarantine_size, u32 max_reuse = 0);
void GetNumberOfThreads(uptr *total = nullptr, uptr *running = nullptr,
@@ -113,7 +111,7 @@ class ThreadRegistry {
void RunCallbackForEachThreadLocked(ThreadCallback cb, void *arg);
typedef bool (*FindThreadCallback)(ThreadContextBase *tctx, void *arg);
- // Finds a thread using the provided callback. Returns kUnknownTid if no
+ // Finds a thread using the provided callback. Returns kInvalidTid if no
// thread is found.
u32 FindThread(FindThreadCallback cb, void *arg);
// Should be guarded by ThreadRegistryLock. Return 0 if no thread
@@ -126,7 +124,8 @@ class ThreadRegistry {
void SetThreadNameByUserId(uptr user_id, const char *name);
void DetachThread(u32 tid, void *arg);
void JoinThread(u32 tid, void *arg);
- void FinishThread(u32 tid);
+ // Finishes thread and returns previous status.
+ ThreadStatus FinishThread(u32 tid);
void StartThread(u32 tid, tid_t os_id, ThreadType thread_type, void *arg);
void SetThreadUserId(u32 tid, uptr user_id);
diff --git a/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.cpp b/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.cpp
index 10748f96420..1f664b6cf5b 100644
--- a/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.cpp
@@ -12,6 +12,7 @@
#include "sanitizer_tls_get_addr.h"
+#include "sanitizer_atomic.h"
#include "sanitizer_flags.h"
#include "sanitizer_platform_interceptors.h"
@@ -42,39 +43,54 @@ static atomic_uintptr_t number_of_live_dtls;
static const uptr kDestroyedThread = -1;
-static inline void DTLS_Deallocate(DTLS::DTV *dtv, uptr size) {
- if (!size) return;
- VReport(2, "__tls_get_addr: DTLS_Deallocate %p %zd\n", dtv, size);
- UnmapOrDie(dtv, size * sizeof(DTLS::DTV));
+static void DTLS_Deallocate(DTLS::DTVBlock *block) {
+ VReport(2, "__tls_get_addr: DTLS_Deallocate %p %zd\n", block);
+ UnmapOrDie(block, sizeof(DTLS::DTVBlock));
atomic_fetch_sub(&number_of_live_dtls, 1, memory_order_relaxed);
}
-static inline void DTLS_Resize(uptr new_size) {
- if (dtls.dtv_size >= new_size) return;
- new_size = RoundUpToPowerOfTwo(new_size);
- new_size = Max(new_size, 4096UL / sizeof(DTLS::DTV));
- DTLS::DTV *new_dtv =
- (DTLS::DTV *)MmapOrDie(new_size * sizeof(DTLS::DTV), "DTLS_Resize");
+static DTLS::DTVBlock *DTLS_NextBlock(atomic_uintptr_t *cur) {
+ uptr v = atomic_load(cur, memory_order_acquire);
+ if (v == kDestroyedThread)
+ return nullptr;
+ DTLS::DTVBlock *next = (DTLS::DTVBlock *)v;
+ if (next)
+ return next;
+ DTLS::DTVBlock *new_dtv =
+ (DTLS::DTVBlock *)MmapOrDie(sizeof(DTLS::DTVBlock), "DTLS_NextBlock");
+ uptr prev = 0;
+ if (!atomic_compare_exchange_strong(cur, &prev, (uptr)new_dtv,
+ memory_order_seq_cst)) {
+ UnmapOrDie(new_dtv, sizeof(DTLS::DTVBlock));
+ return (DTLS::DTVBlock *)prev;
+ }
uptr num_live_dtls =
atomic_fetch_add(&number_of_live_dtls, 1, memory_order_relaxed);
- VReport(2, "__tls_get_addr: DTLS_Resize %p %zd\n", &dtls, num_live_dtls);
- CHECK_LT(num_live_dtls, 1 << 20);
- uptr old_dtv_size = dtls.dtv_size;
- DTLS::DTV *old_dtv = dtls.dtv;
- if (old_dtv_size)
- internal_memcpy(new_dtv, dtls.dtv, dtls.dtv_size * sizeof(DTLS::DTV));
- dtls.dtv = new_dtv;
- dtls.dtv_size = new_size;
- if (old_dtv_size)
- DTLS_Deallocate(old_dtv, old_dtv_size);
+ VReport(2, "__tls_get_addr: DTLS_NextBlock %p %zd\n", &dtls, num_live_dtls);
+ return new_dtv;
+}
+
+static DTLS::DTV *DTLS_Find(uptr id) {
+ VReport(2, "__tls_get_addr: DTLS_Find %p %zd\n", &dtls, id);
+ static constexpr uptr kPerBlock = ARRAY_SIZE(DTLS::DTVBlock::dtvs);
+ DTLS::DTVBlock *cur = DTLS_NextBlock(&dtls.dtv_block);
+ if (!cur)
+ return nullptr;
+ for (; id >= kPerBlock; id -= kPerBlock) cur = DTLS_NextBlock(&cur->next);
+ return cur->dtvs + id;
}
void DTLS_Destroy() {
if (!common_flags()->intercept_tls_get_addr) return;
- VReport(2, "__tls_get_addr: DTLS_Destroy %p %zd\n", &dtls, dtls.dtv_size);
- uptr s = dtls.dtv_size;
- dtls.dtv_size = kDestroyedThread; // Do this before unmap for AS-safety.
- DTLS_Deallocate(dtls.dtv, s);
+ VReport(2, "__tls_get_addr: DTLS_Destroy %p\n", &dtls);
+ DTLS::DTVBlock *block = (DTLS::DTVBlock *)atomic_exchange(
+ &dtls.dtv_block, kDestroyedThread, memory_order_release);
+ while (block) {
+ DTLS::DTVBlock *next =
+ (DTLS::DTVBlock *)atomic_load(&block->next, memory_order_acquire);
+ DTLS_Deallocate(block);
+ block = next;
+ }
}
#if defined(__powerpc64__) || defined(__mips__)
@@ -96,9 +112,9 @@ DTLS::DTV *DTLS_on_tls_get_addr(void *arg_void, void *res,
if (!common_flags()->intercept_tls_get_addr) return 0;
TlsGetAddrParam *arg = reinterpret_cast<TlsGetAddrParam *>(arg_void);
uptr dso_id = arg->dso_id;
- if (dtls.dtv_size == kDestroyedThread) return 0;
- DTLS_Resize(dso_id + 1);
- if (dtls.dtv[dso_id].beg) return 0;
+ DTLS::DTV *dtv = DTLS_Find(dso_id);
+ if (!dtv || dtv->beg)
+ return 0;
uptr tls_size = 0;
uptr tls_beg = reinterpret_cast<uptr>(res) - arg->offset - kDtvOffset;
VReport(2, "__tls_get_addr: %p {%p,%p} => %p; tls_beg: %p; sp: %p "
@@ -126,9 +142,9 @@ DTLS::DTV *DTLS_on_tls_get_addr(void *arg_void, void *res,
// This may happen inside the DTOR of main thread, so just ignore it.
tls_size = 0;
}
- dtls.dtv[dso_id].beg = tls_beg;
- dtls.dtv[dso_id].size = tls_size;
- return dtls.dtv + dso_id;
+ dtv->beg = tls_beg;
+ dtv->size = tls_size;
+ return dtv;
}
void DTLS_on_libc_memalign(void *ptr, uptr size) {
@@ -141,7 +157,8 @@ void DTLS_on_libc_memalign(void *ptr, uptr size) {
DTLS *DTLS_Get() { return &dtls; }
bool DTLSInDestruction(DTLS *dtls) {
- return dtls->dtv_size == kDestroyedThread;
+ return atomic_load(&dtls->dtv_block, memory_order_relaxed) ==
+ kDestroyedThread;
}
#else
diff --git a/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.h b/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.h
index c7cd5a8bffc..a599c0bbc75 100644
--- a/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.h
+++ b/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.h
@@ -28,6 +28,7 @@
#ifndef SANITIZER_TLS_GET_ADDR_H
#define SANITIZER_TLS_GET_ADDR_H
+#include "sanitizer_atomic.h"
#include "sanitizer_common.h"
namespace __sanitizer {
@@ -38,15 +39,31 @@ struct DTLS {
struct DTV {
uptr beg, size;
};
+ struct DTVBlock {
+ atomic_uintptr_t next;
+ DTV dtvs[(4096UL - sizeof(next)) / sizeof(DTLS::DTV)];
+ };
+
+ static_assert(sizeof(DTVBlock) <= 4096UL, "Unexpected block size");
- uptr dtv_size;
- DTV *dtv; // dtv_size elements, allocated by MmapOrDie.
+ atomic_uintptr_t dtv_block;
// Auxiliary fields, don't access them outside sanitizer_tls_get_addr.cpp
uptr last_memalign_size;
uptr last_memalign_ptr;
};
+template <typename Fn>
+void ForEachDVT(DTLS *dtls, const Fn &fn) {
+ DTLS::DTVBlock *block =
+ (DTLS::DTVBlock *)atomic_load(&dtls->dtv_block, memory_order_acquire);
+ while (block) {
+ int id = 0;
+ for (auto &d : block->dtvs) fn(d, id++);
+ block = (DTLS::DTVBlock *)atomic_load(&block->next, memory_order_acquire);
+ }
+}
+
// Returns pointer and size of a linker-allocated TLS block.
// Each block is returned exactly once.
DTLS::DTV *DTLS_on_tls_get_addr(void *arg, void *res, uptr static_tls_begin,
diff --git a/libsanitizer/sanitizer_common/sanitizer_unwind_win.cpp b/libsanitizer/sanitizer_common/sanitizer_unwind_win.cpp
index e2edf428004..7e01c81d042 100644
--- a/libsanitizer/sanitizer_common/sanitizer_unwind_win.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_unwind_win.cpp
@@ -43,6 +43,10 @@ void BufferedStackTrace::UnwindSlow(uptr pc, u32 max_depth) {
trace_buffer[0] = pc;
}
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wframe-larger-than="
+#endif
void BufferedStackTrace::UnwindSlow(uptr pc, void *context, u32 max_depth) {
CHECK(context);
CHECK_GE(max_depth, 2);
@@ -74,6 +78,9 @@ void BufferedStackTrace::UnwindSlow(uptr pc, void *context, u32 max_depth) {
trace_buffer[size++] = (uptr)stack_frame.AddrPC.Offset;
}
}
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
#endif // #if !SANITIZER_GO
#endif // SANITIZER_WINDOWS
diff --git a/libsanitizer/sanitizer_common/sanitizer_win.cpp b/libsanitizer/sanitizer_common/sanitizer_win.cpp
index 85ac2633bde..f383e130fa5 100644
--- a/libsanitizer/sanitizer_common/sanitizer_win.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_win.cpp
@@ -334,8 +334,12 @@ bool MprotectNoAccess(uptr addr, uptr size) {
}
void ReleaseMemoryPagesToOS(uptr beg, uptr end) {
- // This is almost useless on 32-bits.
- // FIXME: add madvise-analog when we move to 64-bits.
+ uptr beg_aligned = RoundDownTo(beg, GetPageSizeCached()),
+ end_aligned = RoundDownTo(end, GetPageSizeCached());
+ CHECK(beg < end); // make sure the region is sane
+ if (beg_aligned == end_aligned) // make sure we're freeing at least 1 page;
+ return;
+ UnmapOrDie((void *)beg, end_aligned - beg_aligned);
}
void SetShadowRegionHugePageMode(uptr addr, uptr size) {
@@ -386,6 +390,12 @@ uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding,
return 0;
}
+uptr MapDynamicShadowAndAliases(uptr shadow_size, uptr alias_size,
+ uptr num_aliases, uptr ring_buffer_size) {
+ CHECK(false && "HWASan aliasing is unimplemented on Windows");
+ return 0;
+}
+
bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) {
MEMORY_BASIC_INFORMATION mbi;
CHECK(VirtualQuery((void *)range_start, &mbi, sizeof(mbi)));
@@ -564,7 +574,7 @@ void Abort() {
// load the image at this address. Therefore, we call it the preferred base. Any
// addresses in the DWARF typically assume that the object has been loaded at
// this address.
-static uptr GetPreferredBase(const char *modname) {
+static uptr GetPreferredBase(const char *modname, char *buf, size_t buf_size) {
fd_t fd = OpenFile(modname, RdOnly, nullptr);
if (fd == kInvalidFd)
return 0;
@@ -586,12 +596,10 @@ static uptr GetPreferredBase(const char *modname) {
// IMAGE_FILE_HEADER
// IMAGE_OPTIONAL_HEADER
// Seek to e_lfanew and read all that data.
- char buf[4 + sizeof(IMAGE_FILE_HEADER) + sizeof(IMAGE_OPTIONAL_HEADER)];
if (::SetFilePointer(fd, dos_header.e_lfanew, nullptr, FILE_BEGIN) ==
INVALID_SET_FILE_POINTER)
return 0;
- if (!ReadFromFile(fd, &buf[0], sizeof(buf), &bytes_read) ||
- bytes_read != sizeof(buf))
+ if (!ReadFromFile(fd, buf, buf_size, &bytes_read) || bytes_read != buf_size)
return 0;
// Check for "PE\0\0" before the PE header.
@@ -633,6 +641,10 @@ void ListOfModules::init() {
}
}
+ InternalMmapVector<char> buf(4 + sizeof(IMAGE_FILE_HEADER) +
+ sizeof(IMAGE_OPTIONAL_HEADER));
+ InternalMmapVector<wchar_t> modname_utf16(kMaxPathLength);
+ InternalMmapVector<char> module_name(kMaxPathLength);
// |num_modules| is the number of modules actually present,
size_t num_modules = bytes_required / sizeof(HMODULE);
for (size_t i = 0; i < num_modules; ++i) {
@@ -642,15 +654,13 @@ void ListOfModules::init() {
continue;
// Get the UTF-16 path and convert to UTF-8.
- wchar_t modname_utf16[kMaxPathLength];
int modname_utf16_len =
- GetModuleFileNameW(handle, modname_utf16, kMaxPathLength);
+ GetModuleFileNameW(handle, &modname_utf16[0], kMaxPathLength);
if (modname_utf16_len == 0)
modname_utf16[0] = '\0';
- char module_name[kMaxPathLength];
- int module_name_len =
- ::WideCharToMultiByte(CP_UTF8, 0, modname_utf16, modname_utf16_len + 1,
- &module_name[0], kMaxPathLength, NULL, NULL);
+ int module_name_len = ::WideCharToMultiByte(
+ CP_UTF8, 0, &modname_utf16[0], modname_utf16_len + 1, &module_name[0],
+ kMaxPathLength, NULL, NULL);
module_name[module_name_len] = '\0';
uptr base_address = (uptr)mi.lpBaseOfDll;
@@ -660,15 +670,16 @@ void ListOfModules::init() {
// RVA when computing the module offset. This helps llvm-symbolizer find the
// right DWARF CU. In the common case that the image is loaded at it's
// preferred address, we will now print normal virtual addresses.
- uptr preferred_base = GetPreferredBase(&module_name[0]);
+ uptr preferred_base =
+ GetPreferredBase(&module_name[0], &buf[0], buf.size());
uptr adjusted_base = base_address - preferred_base;
- LoadedModule cur_module;
- cur_module.set(module_name, adjusted_base);
+ modules_.push_back(LoadedModule());
+ LoadedModule &cur_module = modules_.back();
+ cur_module.set(&module_name[0], adjusted_base);
// We add the whole module as one single address range.
cur_module.addAddressRange(base_address, end_address, /*executable*/ true,
/*writable*/ true);
- modules_.push_back(cur_module);
}
UnmapOrDie(hmodules, modules_buffer_size);
}
@@ -956,22 +967,27 @@ void SignalContext::InitPcSpBp() {
uptr SignalContext::GetAddress() const {
EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD *)siginfo;
- return exception_record->ExceptionInformation[1];
+ if (exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
+ return exception_record->ExceptionInformation[1];
+ return (uptr)exception_record->ExceptionAddress;
}
bool SignalContext::IsMemoryAccess() const {
- return GetWriteFlag() != SignalContext::UNKNOWN;
+ return ((EXCEPTION_RECORD *)siginfo)->ExceptionCode ==
+ EXCEPTION_ACCESS_VIOLATION;
}
-bool SignalContext::IsTrueFaultingAddress() const {
- // FIXME: Provide real implementation for this. See Linux and Mac variants.
- return IsMemoryAccess();
-}
+bool SignalContext::IsTrueFaultingAddress() const { return true; }
SignalContext::WriteFlag SignalContext::GetWriteFlag() const {
EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD *)siginfo;
+
+ // The write flag is only available for access violation exceptions.
+ if (exception_record->ExceptionCode != EXCEPTION_ACCESS_VIOLATION)
+ return SignalContext::UNKNOWN;
+
// The contents of this array are documented at
- // https://msdn.microsoft.com/en-us/library/windows/desktop/aa363082(v=vs.85).aspx
+ // https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-exception_record
// The first element indicates read as 0, write as 1, or execute as 8. The
// second element is the faulting address.
switch (exception_record->ExceptionInformation[0]) {
@@ -1037,10 +1053,24 @@ const char *SignalContext::Describe() const {
}
uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {
- // FIXME: Actually implement this function.
- CHECK_GT(buf_len, 0);
- buf[0] = 0;
- return 0;
+ if (buf_len == 0)
+ return 0;
+
+ // Get the UTF-16 path and convert to UTF-8.
+ InternalMmapVector<wchar_t> binname_utf16(kMaxPathLength);
+ int binname_utf16_len =
+ GetModuleFileNameW(NULL, &binname_utf16[0], kMaxPathLength);
+ if (binname_utf16_len == 0) {
+ buf[0] = '\0';
+ return 0;
+ }
+ int binary_name_len =
+ ::WideCharToMultiByte(CP_UTF8, 0, &binname_utf16[0], binname_utf16_len,
+ buf, buf_len, NULL, NULL);
+ if ((unsigned)binary_name_len == buf_len)
+ --binary_name_len;
+ buf[binary_name_len] = '\0';
+ return binary_name_len;
}
uptr ReadLongProcessName(/*out*/char *buf, uptr buf_len) {
diff --git a/libsanitizer/tsan/tsan_clock.cpp b/libsanitizer/tsan/tsan_clock.cpp
index c91b29cb22b..8e5188392ca 100644
--- a/libsanitizer/tsan/tsan_clock.cpp
+++ b/libsanitizer/tsan/tsan_clock.cpp
@@ -150,7 +150,7 @@ void ThreadClock::acquire(ClockCache *c, SyncClock *src) {
bool acquired = false;
for (unsigned i = 0; i < kDirtyTids; i++) {
SyncClock::Dirty dirty = src->dirty_[i];
- unsigned tid = dirty.tid;
+ unsigned tid = dirty.tid();
if (tid != kInvalidTid) {
if (clk_[tid] < dirty.epoch) {
clk_[tid] = dirty.epoch;
@@ -299,10 +299,10 @@ void ThreadClock::ReleaseStore(ClockCache *c, SyncClock *dst) {
dst->tab_idx_ = cached_idx_;
dst->size_ = cached_size_;
dst->blocks_ = cached_blocks_;
- CHECK_EQ(dst->dirty_[0].tid, kInvalidTid);
+ CHECK_EQ(dst->dirty_[0].tid(), kInvalidTid);
// The cached clock is shared (immutable),
// so this is where we store the current clock.
- dst->dirty_[0].tid = tid_;
+ dst->dirty_[0].set_tid(tid_);
dst->dirty_[0].epoch = clk_[tid_];
dst->release_store_tid_ = tid_;
dst->release_store_reused_ = reused_;
@@ -336,8 +336,7 @@ void ThreadClock::ReleaseStore(ClockCache *c, SyncClock *dst) {
ce.reused = 0;
i++;
}
- for (uptr i = 0; i < kDirtyTids; i++)
- dst->dirty_[i].tid = kInvalidTid;
+ for (uptr i = 0; i < kDirtyTids; i++) dst->dirty_[i].set_tid(kInvalidTid);
dst->release_store_tid_ = tid_;
dst->release_store_reused_ = reused_;
// Rememeber that we don't need to acquire it in future.
@@ -369,10 +368,10 @@ void ThreadClock::UpdateCurrentThread(ClockCache *c, SyncClock *dst) const {
// Update the threads time, but preserve 'acquired' flag.
for (unsigned i = 0; i < kDirtyTids; i++) {
SyncClock::Dirty *dirty = &dst->dirty_[i];
- const unsigned tid = dirty->tid;
+ const unsigned tid = dirty->tid();
if (tid == tid_ || tid == kInvalidTid) {
CPP_STAT_INC(StatClockReleaseFast);
- dirty->tid = tid_;
+ dirty->set_tid(tid_);
dirty->epoch = clk_[tid_];
return;
}
@@ -393,8 +392,8 @@ bool ThreadClock::IsAlreadyAcquired(const SyncClock *src) const {
return false;
for (unsigned i = 0; i < kDirtyTids; i++) {
SyncClock::Dirty dirty = src->dirty_[i];
- if (dirty.tid != kInvalidTid) {
- if (clk_[dirty.tid] < dirty.epoch)
+ if (dirty.tid() != kInvalidTid) {
+ if (clk_[dirty.tid()] < dirty.epoch)
return false;
}
}
@@ -453,8 +452,7 @@ void SyncClock::ResetImpl() {
blocks_ = 0;
release_store_tid_ = kInvalidTid;
release_store_reused_ = 0;
- for (uptr i = 0; i < kDirtyTids; i++)
- dirty_[i].tid = kInvalidTid;
+ for (uptr i = 0; i < kDirtyTids; i++) dirty_[i].set_tid(kInvalidTid);
}
void SyncClock::Resize(ClockCache *c, uptr nclk) {
@@ -503,10 +501,10 @@ void SyncClock::Resize(ClockCache *c, uptr nclk) {
void SyncClock::FlushDirty() {
for (unsigned i = 0; i < kDirtyTids; i++) {
Dirty *dirty = &dirty_[i];
- if (dirty->tid != kInvalidTid) {
- CHECK_LT(dirty->tid, size_);
- elem(dirty->tid).epoch = dirty->epoch;
- dirty->tid = kInvalidTid;
+ if (dirty->tid() != kInvalidTid) {
+ CHECK_LT(dirty->tid(), size_);
+ elem(dirty->tid()).epoch = dirty->epoch;
+ dirty->set_tid(kInvalidTid);
}
}
}
@@ -559,7 +557,7 @@ ALWAYS_INLINE bool SyncClock::Cachable() const {
if (size_ == 0)
return false;
for (unsigned i = 0; i < kDirtyTids; i++) {
- if (dirty_[i].tid != kInvalidTid)
+ if (dirty_[i].tid() != kInvalidTid)
return false;
}
return atomic_load_relaxed(ref_ptr(tab_)) == 1;
@@ -606,7 +604,7 @@ ALWAYS_INLINE void SyncClock::append_block(u32 idx) {
u64 SyncClock::get(unsigned tid) const {
for (unsigned i = 0; i < kDirtyTids; i++) {
Dirty dirty = dirty_[i];
- if (dirty.tid == tid)
+ if (dirty.tid() == tid)
return dirty.epoch;
}
return elem(tid).epoch;
@@ -625,9 +623,8 @@ void SyncClock::DebugDump(int(*printf)(const char *s, ...)) {
for (uptr i = 0; i < size_; i++)
printf("%s%llu", i == 0 ? "" : ",", elem(i).reused);
printf("] release_store_tid=%d/%d dirty_tids=%d[%llu]/%d[%llu]",
- release_store_tid_, release_store_reused_,
- dirty_[0].tid, dirty_[0].epoch,
- dirty_[1].tid, dirty_[1].epoch);
+ release_store_tid_, release_store_reused_, dirty_[0].tid(),
+ dirty_[0].epoch, dirty_[1].tid(), dirty_[1].epoch);
}
void SyncClock::Iter::Next() {
diff --git a/libsanitizer/tsan/tsan_clock.h b/libsanitizer/tsan/tsan_clock.h
index 736cdae06ba..31376a1bc9e 100644
--- a/libsanitizer/tsan/tsan_clock.h
+++ b/libsanitizer/tsan/tsan_clock.h
@@ -17,7 +17,7 @@
namespace __tsan {
-typedef DenseSlabAlloc<ClockBlock, 1<<16, 1<<10> ClockAlloc;
+typedef DenseSlabAlloc<ClockBlock, 1 << 22, 1 << 10> ClockAlloc;
typedef DenseSlabAllocCache ClockCache;
// The clock that lives in sync variables (mutexes, atomics, etc).
@@ -65,10 +65,20 @@ class SyncClock {
static const uptr kDirtyTids = 2;
struct Dirty {
- u64 epoch : kClkBits;
- u64 tid : 64 - kClkBits; // kInvalidId if not active
+ u32 tid() const { return tid_ == kShortInvalidTid ? kInvalidTid : tid_; }
+ void set_tid(u32 tid) {
+ tid_ = tid == kInvalidTid ? kShortInvalidTid : tid;
+ }
+ u64 epoch : kClkBits;
+
+ private:
+ // Full kInvalidTid won't fit into Dirty::tid.
+ static const u64 kShortInvalidTid = (1ull << (64 - kClkBits)) - 1;
+ u64 tid_ : 64 - kClkBits; // kInvalidId if not active
};
+ static_assert(sizeof(Dirty) == 8, "Dirty is not 64bit");
+
unsigned release_store_tid_;
unsigned release_store_reused_;
Dirty dirty_[kDirtyTids];
diff --git a/libsanitizer/tsan/tsan_defs.h b/libsanitizer/tsan/tsan_defs.h
index 293d7deccc3..f53787aeba9 100644
--- a/libsanitizer/tsan/tsan_defs.h
+++ b/libsanitizer/tsan/tsan_defs.h
@@ -98,8 +98,6 @@ const bool kCollectHistory = false;
const bool kCollectHistory = true;
#endif
-const u16 kInvalidTid = kMaxTid + 1;
-
// The following "build consistency" machinery ensures that all source files
// are built in the same configuration. Inconsistent builds lead to
// hard to debug crashes.
diff --git a/libsanitizer/tsan/tsan_dense_alloc.h b/libsanitizer/tsan/tsan_dense_alloc.h
index 64fc50e95c2..6c89e405980 100644
--- a/libsanitizer/tsan/tsan_dense_alloc.h
+++ b/libsanitizer/tsan/tsan_dense_alloc.h
@@ -29,28 +29,40 @@ class DenseSlabAllocCache {
typedef u32 IndexT;
uptr pos;
IndexT cache[kSize];
- template<typename T, uptr kL1Size, uptr kL2Size> friend class DenseSlabAlloc;
+ template <typename, uptr, uptr, u64>
+ friend class DenseSlabAlloc;
};
-template<typename T, uptr kL1Size, uptr kL2Size>
+template <typename T, uptr kL1Size, uptr kL2Size, u64 kReserved = 0>
class DenseSlabAlloc {
public:
typedef DenseSlabAllocCache Cache;
typedef typename Cache::IndexT IndexT;
- explicit DenseSlabAlloc(const char *name) {
- // Check that kL1Size and kL2Size are sane.
- CHECK_EQ(kL1Size & (kL1Size - 1), 0);
- CHECK_EQ(kL2Size & (kL2Size - 1), 0);
- CHECK_GE(1ull << (sizeof(IndexT) * 8), kL1Size * kL2Size);
- // Check that it makes sense to use the dense alloc.
- CHECK_GE(sizeof(T), sizeof(IndexT));
- internal_memset(map_, 0, sizeof(map_));
+ static_assert((kL1Size & (kL1Size - 1)) == 0,
+ "kL1Size must be a power-of-two");
+ static_assert((kL2Size & (kL2Size - 1)) == 0,
+ "kL2Size must be a power-of-two");
+ static_assert((kL1Size * kL2Size) <= (1ull << (sizeof(IndexT) * 8)),
+ "kL1Size/kL2Size are too large");
+ static_assert(((kL1Size * kL2Size - 1) & kReserved) == 0,
+ "reserved bits don't fit");
+ static_assert(sizeof(T) > sizeof(IndexT),
+ "it doesn't make sense to use dense alloc");
+
+ explicit DenseSlabAlloc(LinkerInitialized, const char *name) {
freelist_ = 0;
fillpos_ = 0;
name_ = name;
}
+ explicit DenseSlabAlloc(const char *name)
+ : DenseSlabAlloc(LINKER_INITIALIZED, name) {
+ // It can be very large.
+ // Don't page it in for linker initialized objects.
+ internal_memset(map_, 0, sizeof(map_));
+ }
+
~DenseSlabAlloc() {
for (uptr i = 0; i < kL1Size; i++) {
if (map_[i] != 0)
diff --git a/libsanitizer/tsan/tsan_external.cpp b/libsanitizer/tsan/tsan_external.cpp
index 466b2bf0f66..a87e12f2936 100644
--- a/libsanitizer/tsan/tsan_external.cpp
+++ b/libsanitizer/tsan/tsan_external.cpp
@@ -111,12 +111,12 @@ void __tsan_external_assign_tag(void *addr, void *tag) {
SANITIZER_INTERFACE_ATTRIBUTE
void __tsan_external_read(void *addr, void *caller_pc, void *tag) {
- ExternalAccess(addr, STRIP_PC(caller_pc), tag, MemoryRead);
+ ExternalAccess(addr, STRIP_PAC_PC(caller_pc), tag, MemoryRead);
}
SANITIZER_INTERFACE_ATTRIBUTE
void __tsan_external_write(void *addr, void *caller_pc, void *tag) {
- ExternalAccess(addr, STRIP_PC(caller_pc), tag, MemoryWrite);
+ ExternalAccess(addr, STRIP_PAC_PC(caller_pc), tag, MemoryWrite);
}
} // extern "C"
diff --git a/libsanitizer/tsan/tsan_interceptors_mac.cpp b/libsanitizer/tsan/tsan_interceptors_mac.cpp
index aa29536d861..ed10fccc980 100644
--- a/libsanitizer/tsan/tsan_interceptors_mac.cpp
+++ b/libsanitizer/tsan/tsan_interceptors_mac.cpp
@@ -438,6 +438,7 @@ struct fake_shared_weak_count {
virtual void on_zero_shared() = 0;
virtual void _unused_0x18() = 0;
virtual void on_zero_shared_weak() = 0;
+ virtual ~fake_shared_weak_count() = 0; // suppress -Wnon-virtual-dtor
};
} // namespace
diff --git a/libsanitizer/tsan/tsan_interceptors_posix.cpp b/libsanitizer/tsan/tsan_interceptors_posix.cpp
index aa04d8dfb67..2651e22c39f 100644
--- a/libsanitizer/tsan/tsan_interceptors_posix.cpp
+++ b/libsanitizer/tsan/tsan_interceptors_posix.cpp
@@ -54,10 +54,6 @@ using namespace __tsan;
#define vfork __vfork14
#endif
-#if SANITIZER_ANDROID
-#define mallopt(a, b)
-#endif
-
#ifdef __mips__
const int kSigCount = 129;
#else
@@ -85,6 +81,8 @@ extern "C" int pthread_attr_init(void *attr);
extern "C" int pthread_attr_destroy(void *attr);
DECLARE_REAL(int, pthread_attr_getdetachstate, void *, void *)
extern "C" int pthread_attr_setstacksize(void *attr, uptr stacksize);
+extern "C" int pthread_atfork(void (*prepare)(void), void (*parent)(void),
+ void (*child)(void));
extern "C" int pthread_key_create(unsigned *key, void (*destructor)(void* v));
extern "C" int pthread_setspecific(unsigned key, const void *v);
DECLARE_REAL(int, pthread_mutexattr_gettype, void *, void *)
@@ -97,7 +95,7 @@ extern "C" void _exit(int status);
extern "C" int fileno_unlocked(void *stream);
extern "C" int dirfd(void *dirp);
#endif
-#if !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_NETBSD
+#if SANITIZER_GLIBC
extern "C" int mallopt(int param, int value);
#endif
#if SANITIZER_NETBSD
@@ -659,8 +657,11 @@ TSAN_INTERCEPTOR(void*, malloc, uptr size) {
return p;
}
+// In glibc<2.25, dynamic TLS blocks are allocated by __libc_memalign. Intercept
+// __libc_memalign so that (1) we can detect races (2) free will not be called
+// on libc internally allocated blocks.
TSAN_INTERCEPTOR(void*, __libc_memalign, uptr align, uptr sz) {
- SCOPED_TSAN_INTERCEPTOR(__libc_memalign, align, sz);
+ SCOPED_INTERCEPTOR_RAW(__libc_memalign, align, sz);
return user_memalign(thr, pc, align, sz);
}
@@ -773,6 +774,11 @@ static void *mmap_interceptor(ThreadState *thr, uptr pc, Mmap real_mmap,
if (!fix_mmap_addr(&addr, sz, flags)) return MAP_FAILED;
void *res = real_mmap(addr, sz, prot, flags, fd, off);
if (res != MAP_FAILED) {
+ if (!IsAppMem((uptr)res) || !IsAppMem((uptr)res + sz - 1)) {
+ Report("ThreadSanitizer: mmap at bad address: addr=%p size=%p res=%p\n",
+ addr, (void*)sz, res);
+ Die();
+ }
if (fd > 0) FdAccess(thr, pc, fd);
MemoryRangeImitateWriteOrResetRange(thr, pc, (uptr)res, sz);
}
@@ -1122,27 +1128,37 @@ static void *init_cond(void *c, bool force = false) {
return (void*)cond;
}
+namespace {
+
+template <class Fn>
struct CondMutexUnlockCtx {
ScopedInterceptor *si;
ThreadState *thr;
uptr pc;
void *m;
+ void *c;
+ const Fn &fn;
+
+ int Cancel() const { return fn(); }
+ void Unlock() const;
};
-static void cond_mutex_unlock(CondMutexUnlockCtx *arg) {
+template <class Fn>
+void CondMutexUnlockCtx<Fn>::Unlock() const {
// pthread_cond_wait interceptor has enabled async signal delivery
// (see BlockingCall below). Disable async signals since we are running
// tsan code. Also ScopedInterceptor and BlockingCall destructors won't run
// since the thread is cancelled, so we have to manually execute them
// (the thread still can run some user code due to pthread_cleanup_push).
- ThreadSignalContext *ctx = SigCtx(arg->thr);
+ ThreadSignalContext *ctx = SigCtx(thr);
CHECK_EQ(atomic_load(&ctx->in_blocking_func, memory_order_relaxed), 1);
atomic_store(&ctx->in_blocking_func, 0, memory_order_relaxed);
- MutexPostLock(arg->thr, arg->pc, (uptr)arg->m, MutexFlagDoPreLockOnPostLock);
+ MutexPostLock(thr, pc, (uptr)m, MutexFlagDoPreLockOnPostLock);
// Undo BlockingCall ctor effects.
- arg->thr->ignore_interceptors--;
- arg->si->~ScopedInterceptor();
+ thr->ignore_interceptors--;
+ si->~ScopedInterceptor();
}
+} // namespace
INTERCEPTOR(int, pthread_cond_init, void *c, void *a) {
void *cond = init_cond(c, true);
@@ -1151,20 +1167,24 @@ INTERCEPTOR(int, pthread_cond_init, void *c, void *a) {
return REAL(pthread_cond_init)(cond, a);
}
-static int cond_wait(ThreadState *thr, uptr pc, ScopedInterceptor *si,
- int (*fn)(void *c, void *m, void *abstime), void *c,
- void *m, void *t) {
+template <class Fn>
+int cond_wait(ThreadState *thr, uptr pc, ScopedInterceptor *si, const Fn &fn,
+ void *c, void *m) {
MemoryAccessRange(thr, pc, (uptr)c, sizeof(uptr), false);
MutexUnlock(thr, pc, (uptr)m);
- CondMutexUnlockCtx arg = {si, thr, pc, m};
int res = 0;
// This ensures that we handle mutex lock even in case of pthread_cancel.
// See test/tsan/cond_cancel.cpp.
{
// Enable signal delivery while the thread is blocked.
BlockingCall bc(thr);
+ CondMutexUnlockCtx<Fn> arg = {si, thr, pc, m, c, fn};
res = call_pthread_cancel_with_cleanup(
- fn, c, m, t, (void (*)(void *arg))cond_mutex_unlock, &arg);
+ [](void *arg) -> int {
+ return ((const CondMutexUnlockCtx<Fn> *)arg)->Cancel();
+ },
+ [](void *arg) { ((const CondMutexUnlockCtx<Fn> *)arg)->Unlock(); },
+ &arg);
}
if (res == errno_EOWNERDEAD) MutexRepair(thr, pc, (uptr)m);
MutexPostLock(thr, pc, (uptr)m, MutexFlagDoPreLockOnPostLock);
@@ -1174,25 +1194,46 @@ static int cond_wait(ThreadState *thr, uptr pc, ScopedInterceptor *si,
INTERCEPTOR(int, pthread_cond_wait, void *c, void *m) {
void *cond = init_cond(c);
SCOPED_TSAN_INTERCEPTOR(pthread_cond_wait, cond, m);
- return cond_wait(thr, pc, &si, (int (*)(void *c, void *m, void *abstime))REAL(
- pthread_cond_wait),
- cond, m, 0);
+ return cond_wait(
+ thr, pc, &si, [=]() { return REAL(pthread_cond_wait)(cond, m); }, cond,
+ m);
}
INTERCEPTOR(int, pthread_cond_timedwait, void *c, void *m, void *abstime) {
void *cond = init_cond(c);
SCOPED_TSAN_INTERCEPTOR(pthread_cond_timedwait, cond, m, abstime);
- return cond_wait(thr, pc, &si, REAL(pthread_cond_timedwait), cond, m,
- abstime);
+ return cond_wait(
+ thr, pc, &si,
+ [=]() { return REAL(pthread_cond_timedwait)(cond, m, abstime); }, cond,
+ m);
}
+#if SANITIZER_LINUX
+INTERCEPTOR(int, pthread_cond_clockwait, void *c, void *m,
+ __sanitizer_clockid_t clock, void *abstime) {
+ void *cond = init_cond(c);
+ SCOPED_TSAN_INTERCEPTOR(pthread_cond_clockwait, cond, m, clock, abstime);
+ return cond_wait(
+ thr, pc, &si,
+ [=]() { return REAL(pthread_cond_clockwait)(cond, m, clock, abstime); },
+ cond, m);
+}
+#define TSAN_MAYBE_PTHREAD_COND_CLOCKWAIT TSAN_INTERCEPT(pthread_cond_clockwait)
+#else
+#define TSAN_MAYBE_PTHREAD_COND_CLOCKWAIT
+#endif
+
#if SANITIZER_MAC
INTERCEPTOR(int, pthread_cond_timedwait_relative_np, void *c, void *m,
void *reltime) {
void *cond = init_cond(c);
SCOPED_TSAN_INTERCEPTOR(pthread_cond_timedwait_relative_np, cond, m, reltime);
- return cond_wait(thr, pc, &si, REAL(pthread_cond_timedwait_relative_np), cond,
- m, reltime);
+ return cond_wait(
+ thr, pc, &si,
+ [=]() {
+ return REAL(pthread_cond_timedwait_relative_np)(cond, m, reltime);
+ },
+ cond, m);
}
#endif
@@ -1937,7 +1978,8 @@ static void CallUserSignalHandler(ThreadState *thr, bool sync, bool acquire,
// because in async signal processing case (when handler is called directly
// from rtl_generic_sighandler) we have not yet received the reraised
// signal; and it looks too fragile to intercept all ways to reraise a signal.
- if (flags()->report_bugs && !sync && sig != SIGTERM && errno != 99) {
+ if (ShouldReport(thr, ReportTypeErrnoInSignal) && !sync && sig != SIGTERM &&
+ errno != 99) {
VarSizeStackTrace stack;
// StackTrace::GetNestInstructionPc(pc) is used because return address is
// expected, OutputReport() will undo this.
@@ -2107,26 +2149,32 @@ TSAN_INTERCEPTOR(int, fork, int fake) {
if (in_symbolizer())
return REAL(fork)(fake);
SCOPED_INTERCEPTOR_RAW(fork, fake);
+ return REAL(fork)(fake);
+}
+
+void atfork_prepare() {
+ if (in_symbolizer())
+ return;
+ ThreadState *thr = cur_thread();
+ const uptr pc = StackTrace::GetCurrentPc();
ForkBefore(thr, pc);
- int pid;
- {
- // On OS X, REAL(fork) can call intercepted functions (OSSpinLockLock), and
- // we'll assert in CheckNoLocks() unless we ignore interceptors.
- ScopedIgnoreInterceptors ignore;
- pid = REAL(fork)(fake);
- }
- if (pid == 0) {
- // child
- ForkChildAfter(thr, pc);
- FdOnFork(thr, pc);
- } else if (pid > 0) {
- // parent
- ForkParentAfter(thr, pc);
- } else {
- // error
- ForkParentAfter(thr, pc);
- }
- return pid;
+}
+
+void atfork_parent() {
+ if (in_symbolizer())
+ return;
+ ThreadState *thr = cur_thread();
+ const uptr pc = StackTrace::GetCurrentPc();
+ ForkParentAfter(thr, pc);
+}
+
+void atfork_child() {
+ if (in_symbolizer())
+ return;
+ ThreadState *thr = cur_thread();
+ const uptr pc = StackTrace::GetCurrentPc();
+ ForkChildAfter(thr, pc);
+ FdOnFork(thr, pc);
}
TSAN_INTERCEPTOR(int, vfork, int fake) {
@@ -2479,13 +2527,10 @@ static USED void syscall_fd_release(uptr pc, int fd) {
FdRelease(thr, pc, fd);
}
-static void syscall_pre_fork(uptr pc) {
- TSAN_SYSCALL();
- ForkBefore(thr, pc);
-}
+static void syscall_pre_fork(uptr pc) { ForkBefore(cur_thread(), pc); }
static void syscall_post_fork(uptr pc, int pid) {
- TSAN_SYSCALL();
+ ThreadState *thr = cur_thread();
if (pid == 0) {
// child
ForkChildAfter(thr, pc);
@@ -2635,7 +2680,7 @@ void InitializeInterceptors() {
#endif
// Instruct libc malloc to consume less memory.
-#if SANITIZER_LINUX
+#if SANITIZER_GLIBC
mallopt(1, 0); // M_MXFAST
mallopt(-3, 32*1024); // M_MMAP_THRESHOLD
#endif
@@ -2698,6 +2743,8 @@ void InitializeInterceptors() {
TSAN_INTERCEPT_VER(pthread_cond_timedwait, PTHREAD_ABI_BASE);
TSAN_INTERCEPT_VER(pthread_cond_destroy, PTHREAD_ABI_BASE);
+ TSAN_MAYBE_PTHREAD_COND_CLOCKWAIT;
+
TSAN_INTERCEPT(pthread_mutex_init);
TSAN_INTERCEPT(pthread_mutex_destroy);
TSAN_INTERCEPT(pthread_mutex_trylock);
@@ -2799,6 +2846,10 @@ void InitializeInterceptors() {
Printf("ThreadSanitizer: failed to setup atexit callback\n");
Die();
}
+ if (pthread_atfork(atfork_prepare, atfork_parent, atfork_child)) {
+ Printf("ThreadSanitizer: failed to setup atfork callbacks\n");
+ Die();
+ }
#if !SANITIZER_MAC && !SANITIZER_NETBSD && !SANITIZER_FREEBSD
if (pthread_key_create(&interceptor_ctx()->finalize_key, &thread_finalize)) {
diff --git a/libsanitizer/tsan/tsan_interface.cpp b/libsanitizer/tsan/tsan_interface.cpp
index 55f1c9834f7..9bd0e8580b1 100644
--- a/libsanitizer/tsan/tsan_interface.cpp
+++ b/libsanitizer/tsan/tsan_interface.cpp
@@ -40,13 +40,13 @@ void __tsan_write16(void *addr) {
}
void __tsan_read16_pc(void *addr, void *pc) {
- MemoryRead(cur_thread(), STRIP_PC(pc), (uptr)addr, kSizeLog8);
- MemoryRead(cur_thread(), STRIP_PC(pc), (uptr)addr + 8, kSizeLog8);
+ MemoryRead(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, kSizeLog8);
+ MemoryRead(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr + 8, kSizeLog8);
}
void __tsan_write16_pc(void *addr, void *pc) {
- MemoryWrite(cur_thread(), STRIP_PC(pc), (uptr)addr, kSizeLog8);
- MemoryWrite(cur_thread(), STRIP_PC(pc), (uptr)addr + 8, kSizeLog8);
+ MemoryWrite(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, kSizeLog8);
+ MemoryWrite(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr + 8, kSizeLog8);
}
// __tsan_unaligned_read/write calls are emitted by compiler.
diff --git a/libsanitizer/tsan/tsan_interface.h b/libsanitizer/tsan/tsan_interface.h
index 6d7286ca5b8..6e022b56850 100644
--- a/libsanitizer/tsan/tsan_interface.h
+++ b/libsanitizer/tsan/tsan_interface.h
@@ -204,7 +204,7 @@ __extension__ typedef __int128 a128;
#endif
// Part of ABI, do not change.
-// https://github.com/llvm/llvm-project/blob/master/libcxx/include/atomic
+// https://github.com/llvm/llvm-project/blob/main/libcxx/include/atomic
typedef enum {
mo_relaxed,
mo_consume,
@@ -415,6 +415,13 @@ void __tsan_go_atomic32_compare_exchange(ThreadState *thr, uptr cpc, uptr pc,
SANITIZER_INTERFACE_ATTRIBUTE
void __tsan_go_atomic64_compare_exchange(ThreadState *thr, uptr cpc, uptr pc,
u8 *a);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_on_initialize();
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __tsan_on_finalize(int failed);
+
} // extern "C"
} // namespace __tsan
diff --git a/libsanitizer/tsan/tsan_interface_inl.h b/libsanitizer/tsan/tsan_interface_inl.h
index f5d743c1077..5e77d4d3d28 100644
--- a/libsanitizer/tsan/tsan_interface_inl.h
+++ b/libsanitizer/tsan/tsan_interface_inl.h
@@ -51,35 +51,35 @@ void __tsan_write8(void *addr) {
}
void __tsan_read1_pc(void *addr, void *pc) {
- MemoryRead(cur_thread(), STRIP_PC(pc), (uptr)addr, kSizeLog1);
+ MemoryRead(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, kSizeLog1);
}
void __tsan_read2_pc(void *addr, void *pc) {
- MemoryRead(cur_thread(), STRIP_PC(pc), (uptr)addr, kSizeLog2);
+ MemoryRead(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, kSizeLog2);
}
void __tsan_read4_pc(void *addr, void *pc) {
- MemoryRead(cur_thread(), STRIP_PC(pc), (uptr)addr, kSizeLog4);
+ MemoryRead(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, kSizeLog4);
}
void __tsan_read8_pc(void *addr, void *pc) {
- MemoryRead(cur_thread(), STRIP_PC(pc), (uptr)addr, kSizeLog8);
+ MemoryRead(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, kSizeLog8);
}
void __tsan_write1_pc(void *addr, void *pc) {
- MemoryWrite(cur_thread(), STRIP_PC(pc), (uptr)addr, kSizeLog1);
+ MemoryWrite(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, kSizeLog1);
}
void __tsan_write2_pc(void *addr, void *pc) {
- MemoryWrite(cur_thread(), STRIP_PC(pc), (uptr)addr, kSizeLog2);
+ MemoryWrite(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, kSizeLog2);
}
void __tsan_write4_pc(void *addr, void *pc) {
- MemoryWrite(cur_thread(), STRIP_PC(pc), (uptr)addr, kSizeLog4);
+ MemoryWrite(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, kSizeLog4);
}
void __tsan_write8_pc(void *addr, void *pc) {
- MemoryWrite(cur_thread(), STRIP_PC(pc), (uptr)addr, kSizeLog8);
+ MemoryWrite(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, kSizeLog8);
}
void __tsan_vptr_update(void **vptr_p, void *new_val) {
@@ -101,7 +101,7 @@ void __tsan_vptr_read(void **vptr_p) {
}
void __tsan_func_entry(void *pc) {
- FuncEntry(cur_thread(), STRIP_PC(pc));
+ FuncEntry(cur_thread(), STRIP_PAC_PC(pc));
}
void __tsan_func_exit() {
@@ -125,9 +125,9 @@ void __tsan_write_range(void *addr, uptr size) {
}
void __tsan_read_range_pc(void *addr, uptr size, void *pc) {
- MemoryAccessRange(cur_thread(), STRIP_PC(pc), (uptr)addr, size, false);
+ MemoryAccessRange(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, size, false);
}
void __tsan_write_range_pc(void *addr, uptr size, void *pc) {
- MemoryAccessRange(cur_thread(), STRIP_PC(pc), (uptr)addr, size, true);
+ MemoryAccessRange(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, size, true);
}
diff --git a/libsanitizer/tsan/tsan_mman.cpp b/libsanitizer/tsan/tsan_mman.cpp
index 743e67bf2f7..45a39f0f8ec 100644
--- a/libsanitizer/tsan/tsan_mman.cpp
+++ b/libsanitizer/tsan/tsan_mman.cpp
@@ -145,7 +145,7 @@ void AllocatorPrintStats() {
static void SignalUnsafeCall(ThreadState *thr, uptr pc) {
if (atomic_load_relaxed(&thr->in_signal_handler) == 0 ||
- !flags()->report_signal_unsafe)
+ !ShouldReport(thr, ReportTypeSignalUnsafe))
return;
VarSizeStackTrace stack;
ObtainCurrentStack(thr, pc, &stack);
diff --git a/libsanitizer/tsan/tsan_platform.h b/libsanitizer/tsan/tsan_platform.h
index 16169cab666..101522d8fa4 100644
--- a/libsanitizer/tsan/tsan_platform.h
+++ b/libsanitizer/tsan/tsan_platform.h
@@ -23,9 +23,21 @@
namespace __tsan {
+#if defined(__x86_64__)
+#define HAS_48_BIT_ADDRESS_SPACE 1
+#elif SANITIZER_IOSSIM // arm64 iOS simulators (order of #if matters)
+#define HAS_48_BIT_ADDRESS_SPACE 1
+#elif SANITIZER_IOS // arm64 iOS devices (order of #if matters)
+#define HAS_48_BIT_ADDRESS_SPACE 0
+#elif SANITIZER_MAC // arm64 macOS (order of #if matters)
+#define HAS_48_BIT_ADDRESS_SPACE 1
+#else
+#define HAS_48_BIT_ADDRESS_SPACE 0
+#endif
+
#if !SANITIZER_GO
-#if defined(__x86_64__)
+#if HAS_48_BIT_ADDRESS_SPACE
/*
C/C++ on linux/x86_64 and freebsd/x86_64
0000 0000 1000 - 0080 0000 0000: main binary and/or MAP_32BIT mappings (512GB)
@@ -93,7 +105,7 @@ fe00 0000 00 - ff00 0000 00: heap (4 GB)
ff00 0000 00 - ff80 0000 00: - (2 GB)
ff80 0000 00 - ffff ffff ff: modules and main thread stack (<2 GB)
*/
-struct Mapping {
+struct Mapping40 {
static const uptr kMetaShadowBeg = 0x4000000000ull;
static const uptr kMetaShadowEnd = 0x5000000000ull;
static const uptr kTraceMemBeg = 0xb000000000ull;
@@ -114,6 +126,7 @@ struct Mapping {
};
#define TSAN_MID_APP_RANGE 1
+#define TSAN_RUNTIME_VMA 1
#elif defined(__aarch64__) && defined(__APPLE__)
/*
C/C++ on Darwin/iOS/ARM64 (36-bit VMA, 64 GB VM)
@@ -146,7 +159,7 @@ struct Mapping {
static const uptr kVdsoBeg = 0x7000000000000000ull;
};
-#elif defined(__aarch64__)
+#elif defined(__aarch64__) && !defined(__APPLE__)
// AArch64 supports multiple VMA which leads to multiple address transformation
// functions. To support these multiple VMAS transformations and mappings TSAN
// runtime for AArch64 uses an external memory read (vmaSize) to select which
@@ -354,7 +367,7 @@ struct Mapping47 {
#define TSAN_RUNTIME_VMA 1
#endif
-#elif SANITIZER_GO && !SANITIZER_WINDOWS && defined(__x86_64__)
+#elif SANITIZER_GO && !SANITIZER_WINDOWS && HAS_48_BIT_ADDRESS_SPACE
/* Go on linux, darwin and freebsd on x86_64
0000 0000 1000 - 0000 1000 0000: executable
@@ -502,7 +515,7 @@ Go on linux/mips64 (47-bit VMA)
6000 0000 0000 - 6200 0000 0000: traces
6200 0000 0000 - 8000 0000 0000: -
*/
-struct Mapping {
+struct Mapping47 {
static const uptr kMetaShadowBeg = 0x300000000000ull;
static const uptr kMetaShadowEnd = 0x400000000000ull;
static const uptr kTraceMemBeg = 0x600000000000ull;
@@ -512,6 +525,9 @@ struct Mapping {
static const uptr kAppMemBeg = 0x000000001000ull;
static const uptr kAppMemEnd = 0x00e000000000ull;
};
+
+#define TSAN_RUNTIME_VMA 1
+
#else
# error "Unknown platform"
#endif
@@ -592,6 +608,16 @@ uptr MappingArchImpl(void) {
}
DCHECK(0);
return 0;
+#elif defined(__mips64)
+ switch (vmaSize) {
+#if !SANITIZER_GO
+ case 40: return MappingImpl<Mapping40, Type>();
+#else
+ case 47: return MappingImpl<Mapping47, Type>();
+#endif
+ }
+ DCHECK(0);
+ return 0;
#else
return MappingImpl<Mapping, Type>();
#endif
@@ -749,6 +775,16 @@ bool IsAppMem(uptr mem) {
}
DCHECK(0);
return false;
+#elif defined(__mips64)
+ switch (vmaSize) {
+#if !SANITIZER_GO
+ case 40: return IsAppMemImpl<Mapping40>(mem);
+#else
+ case 47: return IsAppMemImpl<Mapping47>(mem);
+#endif
+ }
+ DCHECK(0);
+ return false;
#else
return IsAppMemImpl<Mapping>(mem);
#endif
@@ -780,6 +816,16 @@ bool IsShadowMem(uptr mem) {
}
DCHECK(0);
return false;
+#elif defined(__mips64)
+ switch (vmaSize) {
+#if !SANITIZER_GO
+ case 40: return IsShadowMemImpl<Mapping40>(mem);
+#else
+ case 47: return IsShadowMemImpl<Mapping47>(mem);
+#endif
+ }
+ DCHECK(0);
+ return false;
#else
return IsShadowMemImpl<Mapping>(mem);
#endif
@@ -811,6 +857,16 @@ bool IsMetaMem(uptr mem) {
}
DCHECK(0);
return false;
+#elif defined(__mips64)
+ switch (vmaSize) {
+#if !SANITIZER_GO
+ case 40: return IsMetaMemImpl<Mapping40>(mem);
+#else
+ case 47: return IsMetaMemImpl<Mapping47>(mem);
+#endif
+ }
+ DCHECK(0);
+ return false;
#else
return IsMetaMemImpl<Mapping>(mem);
#endif
@@ -852,6 +908,16 @@ uptr MemToShadow(uptr x) {
}
DCHECK(0);
return 0;
+#elif defined(__mips64)
+ switch (vmaSize) {
+#if !SANITIZER_GO
+ case 40: return MemToShadowImpl<Mapping40>(x);
+#else
+ case 47: return MemToShadowImpl<Mapping47>(x);
+#endif
+ }
+ DCHECK(0);
+ return 0;
#else
return MemToShadowImpl<Mapping>(x);
#endif
@@ -895,6 +961,16 @@ u32 *MemToMeta(uptr x) {
}
DCHECK(0);
return 0;
+#elif defined(__mips64)
+ switch (vmaSize) {
+#if !SANITIZER_GO
+ case 40: return MemToMetaImpl<Mapping40>(x);
+#else
+ case 47: return MemToMetaImpl<Mapping47>(x);
+#endif
+ }
+ DCHECK(0);
+ return 0;
#else
return MemToMetaImpl<Mapping>(x);
#endif
@@ -951,6 +1027,16 @@ uptr ShadowToMem(uptr s) {
}
DCHECK(0);
return 0;
+#elif defined(__mips64)
+ switch (vmaSize) {
+#if !SANITIZER_GO
+ case 40: return ShadowToMemImpl<Mapping40>(s);
+#else
+ case 47: return ShadowToMemImpl<Mapping47>(s);
+#endif
+ }
+ DCHECK(0);
+ return 0;
#else
return ShadowToMemImpl<Mapping>(s);
#endif
@@ -990,6 +1076,16 @@ uptr GetThreadTrace(int tid) {
}
DCHECK(0);
return 0;
+#elif defined(__mips64)
+ switch (vmaSize) {
+#if !SANITIZER_GO
+ case 40: return GetThreadTraceImpl<Mapping40>(tid);
+#else
+ case 47: return GetThreadTraceImpl<Mapping47>(tid);
+#endif
+ }
+ DCHECK(0);
+ return 0;
#else
return GetThreadTraceImpl<Mapping>(tid);
#endif
@@ -1024,6 +1120,16 @@ uptr GetThreadTraceHeader(int tid) {
}
DCHECK(0);
return 0;
+#elif defined(__mips64)
+ switch (vmaSize) {
+#if !SANITIZER_GO
+ case 40: return GetThreadTraceHeaderImpl<Mapping40>(tid);
+#else
+ case 47: return GetThreadTraceHeaderImpl<Mapping47>(tid);
+#endif
+ }
+ DCHECK(0);
+ return 0;
#else
return GetThreadTraceHeaderImpl<Mapping>(tid);
#endif
@@ -1040,9 +1146,8 @@ int ExtractRecvmsgFDs(void *msg, int *fds, int nfd);
uptr ExtractLongJmpSp(uptr *env);
void ImitateTlsWrite(ThreadState *thr, uptr tls_addr, uptr tls_size);
-int call_pthread_cancel_with_cleanup(int(*fn)(void *c, void *m,
- void *abstime), void *c, void *m, void *abstime,
- void(*cleanup)(void *arg), void *arg);
+int call_pthread_cancel_with_cleanup(int (*fn)(void *arg),
+ void (*cleanup)(void *arg), void *arg);
void DestroyThreadState();
void PlatformCleanUpThreadState(ThreadState *thr);
diff --git a/libsanitizer/tsan/tsan_platform_linux.cpp b/libsanitizer/tsan/tsan_platform_linux.cpp
index d136dcb1cec..e5b6690edfd 100644
--- a/libsanitizer/tsan/tsan_platform_linux.cpp
+++ b/libsanitizer/tsan/tsan_platform_linux.cpp
@@ -250,6 +250,20 @@ void InitializePlatformEarly() {
Die();
}
# endif
+#elif defined(__mips64)
+# if !SANITIZER_GO
+ if (vmaSize != 40) {
+ Printf("FATAL: ThreadSanitizer: unsupported VMA range\n");
+ Printf("FATAL: Found %zd - Supported 40\n", vmaSize);
+ Die();
+ }
+# else
+ if (vmaSize != 47) {
+ Printf("FATAL: ThreadSanitizer: unsupported VMA range\n");
+ Printf("FATAL: Found %zd - Supported 47\n", vmaSize);
+ Die();
+ }
+# endif
#endif
#endif
}
@@ -443,14 +457,13 @@ void ImitateTlsWrite(ThreadState *thr, uptr tls_addr, uptr tls_size) {
// Note: this function runs with async signals enabled,
// so it must not touch any tsan state.
-int call_pthread_cancel_with_cleanup(int(*fn)(void *c, void *m,
- void *abstime), void *c, void *m, void *abstime,
- void(*cleanup)(void *arg), void *arg) {
+int call_pthread_cancel_with_cleanup(int (*fn)(void *arg),
+ void (*cleanup)(void *arg), void *arg) {
// pthread_cleanup_push/pop are hardcore macros mess.
// We can't intercept nor call them w/o including pthread.h.
int res;
pthread_cleanup_push(cleanup, arg);
- res = fn(c, m, abstime);
+ res = fn(arg);
pthread_cleanup_pop(0);
return res;
}
@@ -484,7 +497,7 @@ ThreadState *cur_thread() {
dead_thread_state->fast_state.SetIgnoreBit();
dead_thread_state->ignore_interceptors = 1;
dead_thread_state->is_dead = true;
- *const_cast<int*>(&dead_thread_state->tid) = -1;
+ *const_cast<u32*>(&dead_thread_state->tid) = -1;
CHECK_EQ(0, internal_mprotect(dead_thread_state, sizeof(ThreadState),
PROT_READ));
}
diff --git a/libsanitizer/tsan/tsan_platform_mac.cpp b/libsanitizer/tsan/tsan_platform_mac.cpp
index ec2c5fb1621..d9719a136b2 100644
--- a/libsanitizer/tsan/tsan_platform_mac.cpp
+++ b/libsanitizer/tsan/tsan_platform_mac.cpp
@@ -234,7 +234,7 @@ static void my_pthread_introspection_hook(unsigned int event, pthread_t thread,
#endif
void InitializePlatformEarly() {
-#if !SANITIZER_GO && defined(__aarch64__)
+#if !SANITIZER_GO && !HAS_48_BIT_ADDRESS_SPACE
uptr max_vm = GetMaxUserVirtualAddress() + 1;
if (max_vm != Mapping::kHiAppMemEnd) {
Printf("ThreadSanitizer: unsupported vm address limit %p, expected %p.\n",
@@ -306,14 +306,13 @@ void ImitateTlsWrite(ThreadState *thr, uptr tls_addr, uptr tls_size) {
#if !SANITIZER_GO
// Note: this function runs with async signals enabled,
// so it must not touch any tsan state.
-int call_pthread_cancel_with_cleanup(int(*fn)(void *c, void *m,
- void *abstime), void *c, void *m, void *abstime,
- void(*cleanup)(void *arg), void *arg) {
+int call_pthread_cancel_with_cleanup(int (*fn)(void *arg),
+ void (*cleanup)(void *arg), void *arg) {
// pthread_cleanup_push/pop are hardcore macros mess.
// We can't intercept nor call them w/o including pthread.h.
int res;
pthread_cleanup_push(cleanup, arg);
- res = fn(c, m, abstime);
+ res = fn(arg);
pthread_cleanup_pop(0);
return res;
}
diff --git a/libsanitizer/tsan/tsan_platform_posix.cpp b/libsanitizer/tsan/tsan_platform_posix.cpp
index d56b6c3b9c5..73e1d4577c2 100644
--- a/libsanitizer/tsan/tsan_platform_posix.cpp
+++ b/libsanitizer/tsan/tsan_platform_posix.cpp
@@ -99,7 +99,7 @@ void CheckAndProtect() {
Die();
}
-#if defined(__aarch64__) && defined(__APPLE__)
+#if defined(__aarch64__) && defined(__APPLE__) && !HAS_48_BIT_ADDRESS_SPACE
ProtectRange(HeapMemEnd(), ShadowBeg());
ProtectRange(ShadowEnd(), MetaShadowBeg());
ProtectRange(MetaShadowEnd(), TraceMemBeg());
diff --git a/libsanitizer/tsan/tsan_report.cpp b/libsanitizer/tsan/tsan_report.cpp
index 968c7b97553..8ef9f0cd4fe 100644
--- a/libsanitizer/tsan/tsan_report.cpp
+++ b/libsanitizer/tsan/tsan_report.cpp
@@ -69,7 +69,7 @@ ReportDesc::~ReportDesc() {
const int kThreadBufSize = 32;
const char *thread_name(char *buf, int tid) {
- if (tid == 0)
+ if (tid == kMainTid)
return "main thread";
internal_snprintf(buf, kThreadBufSize, "thread T%d", tid);
return buf;
@@ -127,7 +127,7 @@ void PrintStack(const ReportStack *ent) {
}
SymbolizedStack *frame = ent->frames;
for (int i = 0; frame && frame->info.address; frame = frame->next, i++) {
- InternalScopedString res(2 * GetPageSizeCached());
+ InternalScopedString res;
RenderFrame(&res, common_flags()->stack_trace_format, i,
frame->info.address, &frame->info,
common_flags()->symbolize_vs_style,
@@ -250,7 +250,7 @@ static void PrintMutex(const ReportMutex *rm) {
static void PrintThread(const ReportThread *rt) {
Decorator d;
- if (rt->id == 0) // Little sense in describing the main thread.
+ if (rt->id == kMainTid) // Little sense in describing the main thread.
return;
Printf("%s", d.ThreadDescription());
Printf(" Thread T%d", rt->id);
@@ -394,7 +394,7 @@ void PrintReport(const ReportDesc *rep) {
#else // #if !SANITIZER_GO
-const int kMainThreadId = 1;
+const u32 kMainGoroutineId = 1;
void PrintStack(const ReportStack *ent) {
if (ent == 0 || ent->frames == 0) {
@@ -415,7 +415,7 @@ static void PrintMop(const ReportMop *mop, bool first) {
Printf("%s at %p by ",
(first ? (mop->write ? "Write" : "Read")
: (mop->write ? "Previous write" : "Previous read")), mop->addr);
- if (mop->tid == kMainThreadId)
+ if (mop->tid == kMainGoroutineId)
Printf("main goroutine:\n");
else
Printf("goroutine %d:\n", mop->tid);
@@ -428,7 +428,7 @@ static void PrintLocation(const ReportLocation *loc) {
Printf("\n");
Printf("Heap block of size %zu at %p allocated by ",
loc->heap_chunk_size, loc->heap_chunk_start);
- if (loc->tid == kMainThreadId)
+ if (loc->tid == kMainGoroutineId)
Printf("main goroutine:\n");
else
Printf("goroutine %d:\n", loc->tid);
@@ -448,7 +448,7 @@ static void PrintLocation(const ReportLocation *loc) {
}
static void PrintThread(const ReportThread *rt) {
- if (rt->id == kMainThreadId)
+ if (rt->id == kMainGoroutineId)
return;
Printf("\n");
Printf("Goroutine %d (%s) created at:\n",
diff --git a/libsanitizer/tsan/tsan_rtl.cpp b/libsanitizer/tsan/tsan_rtl.cpp
index 3d721eb95a2..0efa99788ab 100644
--- a/libsanitizer/tsan/tsan_rtl.cpp
+++ b/libsanitizer/tsan/tsan_rtl.cpp
@@ -11,17 +11,19 @@
// Main file (entry points) for the TSan run-time.
//===----------------------------------------------------------------------===//
+#include "tsan_rtl.h"
+
#include "sanitizer_common/sanitizer_atomic.h"
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_file.h"
#include "sanitizer_common/sanitizer_libc.h"
-#include "sanitizer_common/sanitizer_stackdepot.h"
#include "sanitizer_common/sanitizer_placement_new.h"
+#include "sanitizer_common/sanitizer_stackdepot.h"
#include "sanitizer_common/sanitizer_symbolizer.h"
#include "tsan_defs.h"
-#include "tsan_platform.h"
-#include "tsan_rtl.h"
+#include "tsan_interface.h"
#include "tsan_mman.h"
+#include "tsan_platform.h"
#include "tsan_suppressions.h"
#include "tsan_symbolize.h"
#include "ubsan/ubsan_init.h"
@@ -56,12 +58,23 @@ Context *ctx;
bool OnFinalize(bool failed);
void OnInitialize();
#else
+#include <dlfcn.h>
SANITIZER_WEAK_CXX_DEFAULT_IMPL
bool OnFinalize(bool failed) {
+#if !SANITIZER_GO
+ if (auto *ptr = dlsym(RTLD_DEFAULT, "__tsan_on_finalize"))
+ return reinterpret_cast<decltype(&__tsan_on_finalize)>(ptr)(failed);
+#endif
return failed;
}
SANITIZER_WEAK_CXX_DEFAULT_IMPL
-void OnInitialize() {}
+void OnInitialize() {
+#if !SANITIZER_GO
+ if (auto *ptr = dlsym(RTLD_DEFAULT, "__tsan_on_initialize")) {
+ return reinterpret_cast<decltype(&__tsan_on_initialize)>(ptr)();
+ }
+#endif
+}
#endif
static char thread_registry_placeholder[sizeof(ThreadRegistry)];
@@ -77,12 +90,19 @@ static ThreadContextBase *CreateThreadContext(u32 tid) {
new((void*)hdr) Trace();
// We are going to use only a small part of the trace with the default
// value of history_size. However, the constructor writes to the whole trace.
- // Unmap the unused part.
+ // Release the unused part.
uptr hdr_end = hdr + sizeof(Trace);
hdr_end -= sizeof(TraceHeader) * (kTraceParts - TraceParts());
hdr_end = RoundUp(hdr_end, GetPageSizeCached());
- if (hdr_end < hdr + sizeof(Trace))
- UnmapOrDie((void*)hdr_end, hdr + sizeof(Trace) - hdr_end);
+ if (hdr_end < hdr + sizeof(Trace)) {
+ ReleaseMemoryPagesToOS(hdr_end, hdr + sizeof(Trace));
+ uptr unused = hdr + sizeof(Trace) - hdr_end;
+ if (hdr_end != (uptr)MmapFixedNoAccess(hdr_end, unused)) {
+ Report("ThreadSanitizer: failed to mprotect(%p, %p)\n",
+ hdr_end, unused);
+ CHECK("unable to mprotect" && 0);
+ }
+ }
void *mem = internal_alloc(MBlockThreadContex, sizeof(ThreadContext));
return new(mem) ThreadContext(tid);
}
@@ -94,42 +114,45 @@ static const u32 kThreadQuarantineSize = 64;
#endif
Context::Context()
- : initialized()
- , report_mtx(MutexTypeReport, StatMtxReport)
- , nreported()
- , nmissed_expected()
- , thread_registry(new(thread_registry_placeholder) ThreadRegistry(
- CreateThreadContext, kMaxTid, kThreadQuarantineSize, kMaxTidReuse))
- , racy_mtx(MutexTypeRacy, StatMtxRacy)
- , racy_stacks()
- , racy_addresses()
- , fired_suppressions_mtx(MutexTypeFired, StatMtxFired)
- , clock_alloc("clock allocator") {
+ : initialized(),
+ report_mtx(MutexTypeReport, StatMtxReport),
+ nreported(),
+ nmissed_expected(),
+ thread_registry(new (thread_registry_placeholder) ThreadRegistry(
+ CreateThreadContext, kMaxTid, kThreadQuarantineSize, kMaxTidReuse)),
+ racy_mtx(MutexTypeRacy, StatMtxRacy),
+ racy_stacks(),
+ racy_addresses(),
+ fired_suppressions_mtx(MutexTypeFired, StatMtxFired),
+ clock_alloc(LINKER_INITIALIZED, "clock allocator") {
fired_suppressions.reserve(8);
}
// The objects are allocated in TLS, so one may rely on zero-initialization.
-ThreadState::ThreadState(Context *ctx, int tid, int unique_id, u64 epoch,
- unsigned reuse_count,
- uptr stk_addr, uptr stk_size,
+ThreadState::ThreadState(Context *ctx, u32 tid, int unique_id, u64 epoch,
+ unsigned reuse_count, uptr stk_addr, uptr stk_size,
uptr tls_addr, uptr tls_size)
- : fast_state(tid, epoch)
- // Do not touch these, rely on zero initialization,
- // they may be accessed before the ctor.
- // , ignore_reads_and_writes()
- // , ignore_interceptors()
- , clock(tid, reuse_count)
+ : fast_state(tid, epoch)
+ // Do not touch these, rely on zero initialization,
+ // they may be accessed before the ctor.
+ // , ignore_reads_and_writes()
+ // , ignore_interceptors()
+ ,
+ clock(tid, reuse_count)
#if !SANITIZER_GO
- , jmp_bufs()
+ ,
+ jmp_bufs()
#endif
- , tid(tid)
- , unique_id(unique_id)
- , stk_addr(stk_addr)
- , stk_size(stk_size)
- , tls_addr(tls_addr)
- , tls_size(tls_size)
+ ,
+ tid(tid),
+ unique_id(unique_id),
+ stk_addr(stk_addr),
+ stk_size(stk_size),
+ tls_addr(tls_addr),
+ tls_size(tls_size)
#if !SANITIZER_GO
- , last_sleep_clock(tid)
+ ,
+ last_sleep_clock(tid)
#endif
{
}
@@ -160,12 +183,12 @@ static void *BackgroundThread(void *arg) {
} else if (internal_strcmp(flags()->profile_memory, "stderr") == 0) {
mprof_fd = 2;
} else {
- InternalScopedString filename(kMaxPathLength);
+ InternalScopedString filename;
filename.append("%s.%d", flags()->profile_memory, (int)internal_getpid());
fd_t fd = OpenFile(filename.data(), WrOnly);
if (fd == kInvalidFd) {
Printf("ThreadSanitizer: failed to open memory profile file '%s'\n",
- &filename[0]);
+ filename.data());
} else {
mprof_fd = fd;
}
@@ -351,6 +374,18 @@ static void TsanOnDeadlySignal(int signo, void *siginfo, void *context) {
}
#endif
+void CheckUnwind() {
+ // There is high probability that interceptors will check-fail as well,
+ // on the other hand there is no sense in processing interceptors
+ // since we are going to die soon.
+ ScopedIgnoreInterceptors ignore;
+#if !SANITIZER_GO
+ cur_thread()->ignore_sync++;
+ cur_thread()->ignore_reads_and_writes++;
+#endif
+ PrintCurrentStackSlow(StackTrace::GetCurrentPc());
+}
+
void Initialize(ThreadState *thr) {
// Thread safe because done before all threads exist.
static bool is_initialized = false;
@@ -361,7 +396,7 @@ void Initialize(ThreadState *thr) {
ScopedIgnoreInterceptors ignore;
SanitizerToolName = "ThreadSanitizer";
// Install tool-specific callbacks in sanitizer_common.
- SetCheckFailedCallback(TsanCheckFailed);
+ SetCheckUnwindCallback(CheckUnwind);
ctx = new(ctx_placeholder) Context;
const char *env_name = SANITIZER_GO ? "GORACE" : "TSAN_OPTIONS";
@@ -499,23 +534,27 @@ int Finalize(ThreadState *thr) {
void ForkBefore(ThreadState *thr, uptr pc) {
ctx->thread_registry->Lock();
ctx->report_mtx.Lock();
- // Ignore memory accesses in the pthread_atfork callbacks.
- // If any of them triggers a data race we will deadlock
- // on the report_mtx.
- // We could ignore interceptors and sync operations as well,
+ // Suppress all reports in the pthread_atfork callbacks.
+ // Reports will deadlock on the report_mtx.
+ // We could ignore sync operations as well,
// but so far it's unclear if it will do more good or harm.
// Unnecessarily ignoring things can lead to false positives later.
- ThreadIgnoreBegin(thr, pc);
+ thr->suppress_reports++;
+ // On OS X, REAL(fork) can call intercepted functions (OSSpinLockLock), and
+ // we'll assert in CheckNoLocks() unless we ignore interceptors.
+ thr->ignore_interceptors++;
}
void ForkParentAfter(ThreadState *thr, uptr pc) {
- ThreadIgnoreEnd(thr, pc); // Begin is in ForkBefore.
+ thr->suppress_reports--; // Enabled in ForkBefore.
+ thr->ignore_interceptors--;
ctx->report_mtx.Unlock();
ctx->thread_registry->Unlock();
}
void ForkChildAfter(ThreadState *thr, uptr pc) {
- ThreadIgnoreEnd(thr, pc); // Begin is in ForkBefore.
+ thr->suppress_reports--; // Enabled in ForkBefore.
+ thr->ignore_interceptors--;
ctx->report_mtx.Unlock();
ctx->thread_registry->Unlock();
diff --git a/libsanitizer/tsan/tsan_rtl.h b/libsanitizer/tsan/tsan_rtl.h
index 04d474e044e..3ae519d34da 100644
--- a/libsanitizer/tsan/tsan_rtl.h
+++ b/libsanitizer/tsan/tsan_rtl.h
@@ -84,9 +84,6 @@ typedef Allocator::AllocatorCache AllocatorCache;
Allocator *allocator();
#endif
-void TsanCheckFailed(const char *file, int line, const char *cond,
- u64 v1, u64 v2);
-
const u64 kShadowRodata = (u64)-1; // .rodata shadow marker
// FastState (from most significant bit):
@@ -406,7 +403,7 @@ struct ThreadState {
#if TSAN_COLLECT_STATS
u64 stat[StatCnt];
#endif
- const int tid;
+ const u32 tid;
const int unique_id;
bool in_symbolizer;
bool in_ignored_lib;
@@ -447,9 +444,8 @@ struct ThreadState {
const ReportDesc *current_report;
- explicit ThreadState(Context *ctx, int tid, int unique_id, u64 epoch,
- unsigned reuse_count,
- uptr stk_addr, uptr stk_size,
+ explicit ThreadState(Context *ctx, u32 tid, int unique_id, u64 epoch,
+ unsigned reuse_count, uptr stk_addr, uptr stk_size,
uptr tls_addr, uptr tls_size);
};
@@ -624,6 +620,7 @@ class ScopedReport : public ScopedReportBase {
ScopedErrorReportLock lock_;
};
+bool ShouldReport(ThreadState *thr, ReportType typ);
ThreadContext *IsThreadStackOrTls(uptr addr, bool *is_stack);
void RestoreStack(int tid, const u64 epoch, VarSizeStackTrace *stk,
MutexSet *mset, uptr *tag = nullptr);
diff --git a/libsanitizer/tsan/tsan_rtl_mutex.cpp b/libsanitizer/tsan/tsan_rtl_mutex.cpp
index 27897f0592b..0a8f3aa3ddb 100644
--- a/libsanitizer/tsan/tsan_rtl_mutex.cpp
+++ b/libsanitizer/tsan/tsan_rtl_mutex.cpp
@@ -51,6 +51,8 @@ static void ReportMutexMisuse(ThreadState *thr, uptr pc, ReportType typ,
// or false positives (e.g. unlock in a different thread).
if (SANITIZER_GO)
return;
+ if (!ShouldReport(thr, typ))
+ return;
ThreadRegistryLock l(ctx->thread_registry);
ScopedReport rep(typ);
rep.AddMutex(mid);
@@ -96,9 +98,8 @@ void MutexDestroy(ThreadState *thr, uptr pc, uptr addr, u32 flagz) {
ctx->dd->MutexInit(&cb, &s->dd);
}
bool unlock_locked = false;
- if (flags()->report_destroy_locked
- && s->owner_tid != SyncVar::kInvalidTid
- && !s->IsFlagSet(MutexFlagBroken)) {
+ if (flags()->report_destroy_locked && s->owner_tid != kInvalidTid &&
+ !s->IsFlagSet(MutexFlagBroken)) {
s->SetFlags(MutexFlagBroken);
unlock_locked = true;
}
@@ -107,7 +108,7 @@ void MutexDestroy(ThreadState *thr, uptr pc, uptr addr, u32 flagz) {
if (!unlock_locked)
s->Reset(thr->proc()); // must not reset it before the report is printed
s->mtx.Unlock();
- if (unlock_locked) {
+ if (unlock_locked && ShouldReport(thr, ReportTypeMutexDestroyLocked)) {
ThreadRegistryLock l(ctx->thread_registry);
ScopedReport rep(ReportTypeMutexDestroyLocked);
rep.AddMutex(mid);
@@ -169,7 +170,7 @@ void MutexPostLock(ThreadState *thr, uptr pc, uptr addr, u32 flagz, int rec) {
thr->fast_state.IncrementEpoch();
TraceAddEvent(thr, thr->fast_state, EventTypeLock, s->GetId());
bool report_double_lock = false;
- if (s->owner_tid == SyncVar::kInvalidTid) {
+ if (s->owner_tid == kInvalidTid) {
CHECK_EQ(s->recursion, 0);
s->owner_tid = thr->tid;
s->last_lock = thr->fast_state.raw();
@@ -229,7 +230,7 @@ int MutexUnlock(ThreadState *thr, uptr pc, uptr addr, u32 flagz) {
s->recursion -= rec;
if (s->recursion == 0) {
StatInc(thr, StatMutexUnlock);
- s->owner_tid = SyncVar::kInvalidTid;
+ s->owner_tid = kInvalidTid;
ReleaseStoreImpl(thr, pc, &s->clock);
} else {
StatInc(thr, StatMutexRecUnlock);
@@ -275,7 +276,7 @@ void MutexPostReadLock(ThreadState *thr, uptr pc, uptr addr, u32 flagz) {
thr->fast_state.IncrementEpoch();
TraceAddEvent(thr, thr->fast_state, EventTypeRLock, s->GetId());
bool report_bad_lock = false;
- if (s->owner_tid != SyncVar::kInvalidTid) {
+ if (s->owner_tid != kInvalidTid) {
if (flags()->report_mutex_bugs && !s->IsFlagSet(MutexFlagBroken)) {
s->SetFlags(MutexFlagBroken);
report_bad_lock = true;
@@ -314,7 +315,7 @@ void MutexReadUnlock(ThreadState *thr, uptr pc, uptr addr) {
thr->fast_state.IncrementEpoch();
TraceAddEvent(thr, thr->fast_state, EventTypeRUnlock, s->GetId());
bool report_bad_unlock = false;
- if (s->owner_tid != SyncVar::kInvalidTid) {
+ if (s->owner_tid != kInvalidTid) {
if (flags()->report_mutex_bugs && !s->IsFlagSet(MutexFlagBroken)) {
s->SetFlags(MutexFlagBroken);
report_bad_unlock = true;
@@ -344,7 +345,7 @@ void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr) {
SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true);
bool write = true;
bool report_bad_unlock = false;
- if (s->owner_tid == SyncVar::kInvalidTid) {
+ if (s->owner_tid == kInvalidTid) {
// Seems to be read unlock.
write = false;
StatInc(thr, StatMutexReadUnlock);
@@ -359,7 +360,7 @@ void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr) {
s->recursion--;
if (s->recursion == 0) {
StatInc(thr, StatMutexUnlock);
- s->owner_tid = SyncVar::kInvalidTid;
+ s->owner_tid = kInvalidTid;
ReleaseStoreImpl(thr, pc, &s->clock);
} else {
StatInc(thr, StatMutexRecUnlock);
@@ -387,7 +388,7 @@ void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr) {
void MutexRepair(ThreadState *thr, uptr pc, uptr addr) {
DPrintf("#%d: MutexRepair %zx\n", thr->tid, addr);
SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true);
- s->owner_tid = SyncVar::kInvalidTid;
+ s->owner_tid = kInvalidTid;
s->recursion = 0;
s->mtx.Unlock();
}
@@ -534,7 +535,7 @@ void AcquireReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c) {
}
void ReportDeadlock(ThreadState *thr, uptr pc, DDReport *r) {
- if (r == 0)
+ if (r == 0 || !ShouldReport(thr, ReportTypeDeadlock))
return;
ThreadRegistryLock l(ctx->thread_registry);
ScopedReport rep(ReportTypeDeadlock);
diff --git a/libsanitizer/tsan/tsan_rtl_ppc64.S b/libsanitizer/tsan/tsan_rtl_ppc64.S
index 9e533a71a9c..8285e21aa1e 100644
--- a/libsanitizer/tsan/tsan_rtl_ppc64.S
+++ b/libsanitizer/tsan/tsan_rtl_ppc64.S
@@ -1,6 +1,5 @@
#include "tsan_ppc_regs.h"
- .machine altivec
.section .text
.hidden __tsan_setjmp
.globl _setjmp
diff --git a/libsanitizer/tsan/tsan_rtl_report.cpp b/libsanitizer/tsan/tsan_rtl_report.cpp
index 208d0df44df..706794fdad1 100644
--- a/libsanitizer/tsan/tsan_rtl_report.cpp
+++ b/libsanitizer/tsan/tsan_rtl_report.cpp
@@ -31,23 +31,6 @@ using namespace __sanitizer;
static ReportStack *SymbolizeStack(StackTrace trace);
-void TsanCheckFailed(const char *file, int line, const char *cond,
- u64 v1, u64 v2) {
- // There is high probability that interceptors will check-fail as well,
- // on the other hand there is no sense in processing interceptors
- // since we are going to die soon.
- ScopedIgnoreInterceptors ignore;
-#if !SANITIZER_GO
- cur_thread()->ignore_sync++;
- cur_thread()->ignore_reads_and_writes++;
-#endif
- Printf("FATAL: ThreadSanitizer CHECK failed: "
- "%s:%d \"%s\" (0x%zx, 0x%zx)\n",
- file, line, cond, (uptr)v1, (uptr)v2);
- PrintCurrentStackSlow(StackTrace::GetCurrentPc());
- Die();
-}
-
// Can be overriden by an application/test to intercept reports.
#ifdef TSAN_EXTERNAL_HOOKS
bool OnReport(const ReportDesc *rep, bool suppressed);
@@ -142,6 +125,34 @@ static ReportStack *SymbolizeStack(StackTrace trace) {
return stack;
}
+bool ShouldReport(ThreadState *thr, ReportType typ) {
+ // We set thr->suppress_reports in the fork context.
+ // Taking any locking in the fork context can lead to deadlocks.
+ // If any locks are already taken, it's too late to do this check.
+ CheckNoLocks(thr);
+ // For the same reason check we didn't lock thread_registry yet.
+ if (SANITIZER_DEBUG)
+ ThreadRegistryLock l(ctx->thread_registry);
+ if (!flags()->report_bugs || thr->suppress_reports)
+ return false;
+ switch (typ) {
+ case ReportTypeSignalUnsafe:
+ return flags()->report_signal_unsafe;
+ case ReportTypeThreadLeak:
+#if !SANITIZER_GO
+ // It's impossible to join phantom threads
+ // in the child after fork.
+ if (ctx->after_multithreaded_fork)
+ return false;
+#endif
+ return flags()->report_thread_leaks;
+ case ReportTypeMutexDestroyLocked:
+ return flags()->report_destroy_locked;
+ default:
+ return true;
+ }
+}
+
ScopedReportBase::ScopedReportBase(ReportType typ, uptr tag) {
ctx->thread_registry->CheckLocked();
void *mem = internal_alloc(MBlockReport, sizeof(ReportDesc));
@@ -497,8 +508,10 @@ static bool HandleRacyAddress(ThreadState *thr, uptr addr_min, uptr addr_max) {
}
bool OutputReport(ThreadState *thr, const ScopedReport &srep) {
- if (!flags()->report_bugs || thr->suppress_reports)
- return false;
+ // These should have been checked in ShouldReport.
+ // It's too late to check them here, we have already taken locks.
+ CHECK(flags()->report_bugs);
+ CHECK(!thr->suppress_reports);
atomic_store_relaxed(&ctx->last_symbolize_time_ns, NanoTime());
const ReportDesc *rep = srep.GetReport();
CHECK_EQ(thr->current_report, nullptr);
@@ -589,7 +602,7 @@ void ReportRace(ThreadState *thr) {
// at best it will cause deadlocks on internal mutexes.
ScopedIgnoreInterceptors ignore;
- if (!flags()->report_bugs)
+ if (!ShouldReport(thr, ReportTypeRace))
return;
if (!flags()->report_atomic_races && !RaceBetweenAtomicAndFree(thr))
return;
@@ -722,8 +735,7 @@ void PrintCurrentStack(ThreadState *thr, uptr pc) {
// However, this solution is not reliable enough, please see dvyukov's comment
// http://reviews.llvm.org/D19148#406208
// Also see PR27280 comment 2 and 3 for breaking examples and analysis.
-ALWAYS_INLINE
-void PrintCurrentStackSlow(uptr pc) {
+ALWAYS_INLINE USED void PrintCurrentStackSlow(uptr pc) {
#if !SANITIZER_GO
uptr bp = GET_CURRENT_FRAME();
BufferedStackTrace *ptrace =
diff --git a/libsanitizer/tsan/tsan_rtl_thread.cpp b/libsanitizer/tsan/tsan_rtl_thread.cpp
index d80146735ea..6d1ccd8c9c7 100644
--- a/libsanitizer/tsan/tsan_rtl_thread.cpp
+++ b/libsanitizer/tsan/tsan_rtl_thread.cpp
@@ -51,7 +51,7 @@ struct OnCreatedArgs {
void ThreadContext::OnCreated(void *arg) {
thr = 0;
- if (tid == 0)
+ if (tid == kMainTid)
return;
OnCreatedArgs *args = static_cast<OnCreatedArgs *>(arg);
if (!args->thr) // GCD workers don't have a parent thread.
@@ -179,7 +179,7 @@ static void MaybeReportThreadLeak(ThreadContextBase *tctx_base, void *arg) {
#if !SANITIZER_GO
static void ReportIgnoresEnabled(ThreadContext *tctx, IgnoreSet *set) {
- if (tctx->tid == 0) {
+ if (tctx->tid == kMainTid) {
Printf("ThreadSanitizer: main thread finished with ignores enabled\n");
} else {
Printf("ThreadSanitizer: thread T%d %s finished with ignores enabled,"
@@ -210,7 +210,7 @@ static void ThreadCheckIgnore(ThreadState *thr) {}
void ThreadFinalize(ThreadState *thr) {
ThreadCheckIgnore(thr);
#if !SANITIZER_GO
- if (!flags()->report_thread_leaks)
+ if (!ShouldReport(thr, ReportTypeThreadLeak))
return;
ThreadRegistryLock l(ctx->thread_registry);
Vector<ThreadLeak> leaks;
@@ -250,9 +250,10 @@ void ThreadStart(ThreadState *thr, int tid, tid_t os_id,
uptr tls_size = 0;
#if !SANITIZER_GO
if (thread_type != ThreadType::Fiber)
- GetThreadStackAndTls(tid == 0, &stk_addr, &stk_size, &tls_addr, &tls_size);
+ GetThreadStackAndTls(tid == kMainTid, &stk_addr, &stk_size, &tls_addr,
+ &tls_size);
- if (tid) {
+ if (tid != kMainTid) {
if (stk_addr && stk_size)
MemoryRangeImitateWrite(thr, /*pc=*/ 1, stk_addr, stk_size);
@@ -313,7 +314,7 @@ static bool ConsumeThreadByUid(ThreadContextBase *tctx, void *arg) {
int ThreadConsumeTid(ThreadState *thr, uptr pc, uptr uid) {
ConsumeThreadContext findCtx = {uid, nullptr};
ctx->thread_registry->FindThread(ConsumeThreadByUid, &findCtx);
- int tid = findCtx.tctx ? findCtx.tctx->tid : ThreadRegistry::kUnknownTid;
+ int tid = findCtx.tctx ? findCtx.tctx->tid : kInvalidTid;
DPrintf("#%d: ThreadTid uid=%zu tid=%d\n", thr->tid, uid, tid);
return tid;
}
diff --git a/libsanitizer/tsan/tsan_sync.cpp b/libsanitizer/tsan/tsan_sync.cpp
index 17ddd50f128..ba24f98ae9f 100644
--- a/libsanitizer/tsan/tsan_sync.cpp
+++ b/libsanitizer/tsan/tsan_sync.cpp
@@ -53,8 +53,8 @@ void SyncVar::Reset(Processor *proc) {
}
MetaMap::MetaMap()
- : block_alloc_("heap block allocator")
- , sync_alloc_("sync allocator") {
+ : block_alloc_(LINKER_INITIALIZED, "heap block allocator"),
+ sync_alloc_(LINKER_INITIALIZED, "sync allocator") {
atomic_store(&uid_gen_, 0, memory_order_relaxed);
}
diff --git a/libsanitizer/tsan/tsan_sync.h b/libsanitizer/tsan/tsan_sync.h
index 47f2739d8de..c4056f684d7 100644
--- a/libsanitizer/tsan/tsan_sync.h
+++ b/libsanitizer/tsan/tsan_sync.h
@@ -50,13 +50,11 @@ enum MutexFlags {
struct SyncVar {
SyncVar();
- static const int kInvalidTid = -1;
-
uptr addr; // overwritten by DenseSlabAlloc freelist
Mutex mtx;
u64 uid; // Globally unique id.
u32 creation_stack_id;
- int owner_tid; // Set only by exclusive owners.
+ u32 owner_tid; // Set only by exclusive owners.
u64 last_lock;
int recursion;
atomic_uint32_t flags;
@@ -130,8 +128,8 @@ class MetaMap {
static const u32 kFlagMask = 3u << 30;
static const u32 kFlagBlock = 1u << 30;
static const u32 kFlagSync = 2u << 30;
- typedef DenseSlabAlloc<MBlock, 1<<16, 1<<12> BlockAlloc;
- typedef DenseSlabAlloc<SyncVar, 1<<16, 1<<10> SyncAlloc;
+ typedef DenseSlabAlloc<MBlock, 1 << 18, 1 << 12, kFlagMask> BlockAlloc;
+ typedef DenseSlabAlloc<SyncVar, 1 << 20, 1 << 10, kFlagMask> SyncAlloc;
BlockAlloc block_alloc_;
SyncAlloc sync_alloc_;
atomic_uint64_t uid_gen_;
diff --git a/libsanitizer/ubsan/ubsan_diag.cpp b/libsanitizer/ubsan/ubsan_diag.cpp
index 1b2828d236d..ef2e495cac8 100644
--- a/libsanitizer/ubsan/ubsan_diag.cpp
+++ b/libsanitizer/ubsan/ubsan_diag.cpp
@@ -278,7 +278,7 @@ static void PrintMemorySnippet(const Decorator &Decor, MemoryLocation Loc,
}
// Emit data.
- InternalScopedString Buffer(1024);
+ InternalScopedString Buffer;
for (uptr P = Min; P != Max; ++P) {
unsigned char C = *reinterpret_cast<const unsigned char*>(P);
Buffer.append("%s%02x", (P % 8 == 0) ? " " : " ", C);
@@ -346,7 +346,7 @@ Diag::~Diag() {
// All diagnostics should be printed under report mutex.
ScopedReport::CheckLocked();
Decorator Decor;
- InternalScopedString Buffer(1024);
+ InternalScopedString Buffer;
// Prepare a report that a monitor process can inspect.
if (Level == DL_Error) {
@@ -388,6 +388,10 @@ ScopedReport::ScopedReport(ReportOptions Opts, Location SummaryLoc,
ScopedReport::~ScopedReport() {
MaybePrintStackTrace(Opts.pc, Opts.bp);
MaybeReportErrorSummary(SummaryLoc, Type);
+
+ if (common_flags()->print_module_map >= 2)
+ DumpProcessMap();
+
if (flags()->halt_on_error)
Die();
}
diff --git a/libsanitizer/ubsan/ubsan_flags.cpp b/libsanitizer/ubsan/ubsan_flags.cpp
index 9a66bd37518..25cefd46ce2 100644
--- a/libsanitizer/ubsan/ubsan_flags.cpp
+++ b/libsanitizer/ubsan/ubsan_flags.cpp
@@ -50,7 +50,6 @@ void InitializeFlags() {
{
CommonFlags cf;
cf.CopyFrom(*common_flags());
- cf.print_summary = false;
cf.external_symbolizer_path = GetFlag("UBSAN_SYMBOLIZER_PATH");
OverrideCommonFlags(cf);
}
diff --git a/libsanitizer/ubsan/ubsan_handlers.cpp b/libsanitizer/ubsan/ubsan_handlers.cpp
index 2184625aa6e..e201e6bba22 100644
--- a/libsanitizer/ubsan/ubsan_handlers.cpp
+++ b/libsanitizer/ubsan/ubsan_handlers.cpp
@@ -894,21 +894,6 @@ void __ubsan_handle_cfi_bad_type(CFICheckFailData *Data, ValueHandle Vtable,
} // namespace __ubsan
-void __ubsan::__ubsan_handle_cfi_bad_icall(CFIBadIcallData *CallData,
- ValueHandle Function) {
- GET_REPORT_OPTIONS(false);
- CFICheckFailData Data = {CFITCK_ICall, CallData->Loc, CallData->Type};
- handleCFIBadIcall(&Data, Function, Opts);
-}
-
-void __ubsan::__ubsan_handle_cfi_bad_icall_abort(CFIBadIcallData *CallData,
- ValueHandle Function) {
- GET_REPORT_OPTIONS(true);
- CFICheckFailData Data = {CFITCK_ICall, CallData->Loc, CallData->Type};
- handleCFIBadIcall(&Data, Function, Opts);
- Die();
-}
-
void __ubsan::__ubsan_handle_cfi_check_fail(CFICheckFailData *Data,
ValueHandle Value,
uptr ValidVtable) {
diff --git a/libsanitizer/ubsan/ubsan_handlers.h b/libsanitizer/ubsan/ubsan_handlers.h
index 9f412353fc0..219fb15de55 100644
--- a/libsanitizer/ubsan/ubsan_handlers.h
+++ b/libsanitizer/ubsan/ubsan_handlers.h
@@ -215,20 +215,12 @@ enum CFITypeCheckKind : unsigned char {
CFITCK_VMFCall,
};
-struct CFIBadIcallData {
- SourceLocation Loc;
- const TypeDescriptor &Type;
-};
-
struct CFICheckFailData {
CFITypeCheckKind CheckKind;
SourceLocation Loc;
const TypeDescriptor &Type;
};
-/// \brief Handle control flow integrity failure for indirect function calls.
-RECOVERABLE(cfi_bad_icall, CFIBadIcallData *Data, ValueHandle Function)
-
/// \brief Handle control flow integrity failures.
RECOVERABLE(cfi_check_fail, CFICheckFailData *Data, ValueHandle Function,
uptr VtableIsValid)
diff --git a/libsanitizer/ubsan/ubsan_init.cpp b/libsanitizer/ubsan/ubsan_init.cpp
index e0be5a72ec4..9931d85bf40 100644
--- a/libsanitizer/ubsan/ubsan_init.cpp
+++ b/libsanitizer/ubsan/ubsan_init.cpp
@@ -33,6 +33,11 @@ static void CommonInit() {
InitializeSuppressions();
}
+static void UbsanDie() {
+ if (common_flags()->print_module_map >= 1)
+ DumpProcessMap();
+}
+
static void CommonStandaloneInit() {
SanitizerToolName = GetSanititizerToolName();
CacheBinaryName();
@@ -42,6 +47,10 @@ static void CommonStandaloneInit() {
AndroidLogInit();
InitializeCoverage(common_flags()->coverage, common_flags()->coverage_dir);
CommonInit();
+
+ // Only add die callback when running in standalone mode to avoid printing
+ // the same information from multiple sanitizers' output
+ AddDieCallback(UbsanDie);
Symbolizer::LateInitialize();
}
diff --git a/libsanitizer/ubsan/ubsan_monitor.cpp b/libsanitizer/ubsan/ubsan_monitor.cpp
index d064e95f76f..69dd986f9bd 100644
--- a/libsanitizer/ubsan/ubsan_monitor.cpp
+++ b/libsanitizer/ubsan/ubsan_monitor.cpp
@@ -17,7 +17,7 @@ using namespace __ubsan;
UndefinedBehaviorReport::UndefinedBehaviorReport(const char *IssueKind,
Location &Loc,
InternalScopedString &Msg)
- : IssueKind(IssueKind), Loc(Loc), Buffer(Msg.length() + 1) {
+ : IssueKind(IssueKind), Loc(Loc) {
// We have the common sanitizer reporting lock, so it's safe to register a
// new UB report.
RegisterUndefinedBehaviorReport(this);
@@ -52,9 +52,9 @@ void __ubsan::__ubsan_get_current_report_data(const char **OutIssueKind,
// Ensure that the first character of the diagnostic text can't start with a
// lowercase letter.
- char FirstChar = Buf.data()[0];
+ char FirstChar = *Buf.data();
if (FirstChar >= 'a' && FirstChar <= 'z')
- Buf.data()[0] = FirstChar - 'a' + 'A';
+ *Buf.data() += 'A' - 'a';
*OutIssueKind = CurrentUBR->IssueKind;
*OutMessage = Buf.data();
diff --git a/libsanitizer/ubsan/ubsan_platform.h b/libsanitizer/ubsan/ubsan_platform.h
index 98542fcea96..51e535d1e22 100644
--- a/libsanitizer/ubsan/ubsan_platform.h
+++ b/libsanitizer/ubsan/ubsan_platform.h
@@ -12,16 +12,14 @@
#ifndef UBSAN_PLATFORM_H
#define UBSAN_PLATFORM_H
-#ifndef CAN_SANITIZE_UB
// Other platforms should be easy to add, and probably work as-is.
#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || \
- defined(__NetBSD__) || \
+ defined(__NetBSD__) || defined(__DragonFly__) || \
(defined(__sun__) && defined(__svr4__)) || \
defined(_WIN32) || defined(__Fuchsia__) || defined(__rtems__)
# define CAN_SANITIZE_UB 1
#else
# define CAN_SANITIZE_UB 0
#endif
-#endif //CAN_SANITIZE_UB
#endif
--
2.31.1
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH] libsanitizer: merge from master
2021-05-13 7:28 [PATCH] libsanitizer: merge from master Martin Liška
@ 2021-05-13 15:54 ` H.J. Lu
2021-05-13 17:27 ` Martin Liška
2021-06-04 7:32 ` [PATCH] libsanitizer: merge from master Hongtao Liu
1 sibling, 1 reply; 17+ messages in thread
From: H.J. Lu @ 2021-05-13 15:54 UTC (permalink / raw)
To: Martin Liška; +Cc: GCC Patches
On Thu, May 13, 2021 at 09:28:01AM +0200, Martin Liška wrote:
> I'm planning to do merge from master twice a year.
> This merge was tested on x86_64-linux-gnu and ppc64le-linux-gnu
> and survives regression tests.
>
> Pushed to master.
> Thanks,
> Martin
>
> Merged revision: f58e0513dd95944b81ce7a6e7b49ba656de7d75f
On Linux/x86-64, I got
../../../../../src-master/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp: In function ??void __sanitizer::InitTlsSize()??:
../../../../../src-master/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp:209:55: error: invalid conversion from ??__sanitizer::uptr*?? {aka ??long unsigned int*??} to ??size_t*?? {aka ??unsigned int*??} [-fpermissive]
209 | ((void (*)(size_t *, size_t *))get_tls_static_info)(&g_tls_size, &tls_align);
| ^~~~~~~~~~~
| |
| __sanitizer::uptr* {aka long unsigned int*}
H.J.
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH] libsanitizer: merge from master
2021-05-13 15:54 ` H.J. Lu
@ 2021-05-13 17:27 ` Martin Liška
2021-05-13 20:01 ` H.J. Lu
0 siblings, 1 reply; 17+ messages in thread
From: Martin Liška @ 2021-05-13 17:27 UTC (permalink / raw)
To: H.J. Lu; +Cc: GCC Patches
On 5/13/21 5:54 PM, H.J. Lu wrote:
> On Thu, May 13, 2021 at 09:28:01AM +0200, Martin Liška wrote:
>> I'm planning to do merge from master twice a year.
>> This merge was tested on x86_64-linux-gnu and ppc64le-linux-gnu
>> and survives regression tests.
>>
>> Pushed to master.
>> Thanks,
>> Martin
>>
>> Merged revision: f58e0513dd95944b81ce7a6e7b49ba656de7d75f
>
> On Linux/x86-64, I got
>
> ../../../../../src-master/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp: In function ??void __sanitizer::InitTlsSize()??:
> ../../../../../src-master/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp:209:55: error: invalid conversion from ??__sanitizer::uptr*?? {aka ??long unsigned int*??} to ??size_t*?? {aka ??unsigned int*??} [-fpermissive]
> 209 | ((void (*)(size_t *, size_t *))get_tls_static_info)(&g_tls_size, &tls_align);
> | ^~~~~~~~~~~
> | |
> | __sanitizer::uptr* {aka long unsigned int*}
>
>
> H.J.
>
Hm, I can't reproduce it:
/dev/shm/objdir/./gcc/xgcc -shared-libgcc -B/dev/shm/objdir/./gcc -nostdinc++ -L/dev/shm/objdir/x86_64-pc-linux-gnu/libstdc++-v3/src -L/dev/shm/objdir/x86_64-pc-linux-gnu/libstdc++-v3/src/.libs -L/dev/shm/objdir/x86_64-pc-linux-gnu/libstdc++-v3/libsupc++/.libs -B/home/marxin/bin/gcc/x86_64-pc-linux-gnu/bin/ -B/home/marxin/bin/gcc/x86_64-pc-linux-gnu/lib/ -isystem /home/marxin/bin/gcc/x86_64-pc-linux-gnu/include -isystem /home/marxin/bin/gcc/x86_64-pc-linux-gnu/sys-include -D_GNU_SOURCE -D_DEBUG -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -DHAVE_RPC_XDR_H=0 -DHAVE_TIRPC_RPC_XDR_H=0 -I. -I/home/marxin/Programming/gcc/libsanitizer/sanitizer_common -I.. -I /home/marxin/Programming/gcc/libsanitizer/include -I /home/marxin/Programming/gcc/libsanitizer -isystem /home/marxin/Programming/gcc/libsanitizer/include/system -Wall -W -Wno-unused-parameter -Wwrite-strings -pedantic -Wno-long-long -fPIC -fno-builtin -fno-exceptions -fno-rtti -fomit-frame-pointer -funwind-tables -fvisibility=hidden -Wno-variadic-macros -I../../libstdc++-v3/include -I../../libstdc++-v3/include/x86_64-pc-linux-gnu -I/home/marxin/Programming/gcc/libsanitizer/../libstdc++-v3/libsupc++ -std=gnu++14 -fcf-protection -mshstk -DSANITIZER_LIBBACKTRACE -DSANITIZER_CP_DEMANGLE -I /home/marxin/Programming/gcc/libsanitizer/../libbacktrace -I ../libbacktrace -I /home/marxin/Programming/gcc/libsanitizer/../include -include /home/marxin/Programming/gcc/libsanitizer/libbacktrace/backtrace-rename.h -g -O2 -D_GNU_SOURCE -MT sanitizer_linux_libcdep.lo -MD -MP -MF .deps/sanitizer_linux_libcdep.Tpo -c /home/marxin/Programming/gcc/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp -fPIC -DPIC -o .libs/sanitizer_linux_libcdep.o
Can you please show full command line? And please attach a pre-processed source file.
Thanks,
Martin
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH] libsanitizer: merge from master
2021-05-13 17:27 ` Martin Liška
@ 2021-05-13 20:01 ` H.J. Lu
2021-05-13 20:11 ` H.J. Lu
0 siblings, 1 reply; 17+ messages in thread
From: H.J. Lu @ 2021-05-13 20:01 UTC (permalink / raw)
To: Martin Liška; +Cc: GCC Patches
On Thu, May 13, 2021 at 10:27 AM Martin Liška <mliska@suse.cz> wrote:
>
> On 5/13/21 5:54 PM, H.J. Lu wrote:
> > On Thu, May 13, 2021 at 09:28:01AM +0200, Martin Liška wrote:
> >> I'm planning to do merge from master twice a year.
> >> This merge was tested on x86_64-linux-gnu and ppc64le-linux-gnu
> >> and survives regression tests.
> >>
> >> Pushed to master.
> >> Thanks,
> >> Martin
> >>
> >> Merged revision: f58e0513dd95944b81ce7a6e7b49ba656de7d75f
> >
> > On Linux/x86-64, I got
> >
> > ../../../../../src-master/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp: In function ??void __sanitizer::InitTlsSize()??:
> > ../../../../../src-master/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp:209:55: error: invalid conversion from ??__sanitizer::uptr*?? {aka ??long unsigned int*??} to ??size_t*?? {aka ??unsigned int*??} [-fpermissive]
> > 209 | ((void (*)(size_t *, size_t *))get_tls_static_info)(&g_tls_size, &tls_align);
> > | ^~~~~~~~~~~
> > | |
> > | __sanitizer::uptr* {aka long unsigned int*}
> >
> >
> > H.J.
> >
>
> Hm, I can't reproduce it:
>
> /dev/shm/objdir/./gcc/xgcc -shared-libgcc -B/dev/shm/objdir/./gcc -nostdinc++ -L/dev/shm/objdir/x86_64-pc-linux-gnu/libstdc++-v3/src -L/dev/shm/objdir/x86_64-pc-linux-gnu/libstdc++-v3/src/.libs -L/dev/shm/objdir/x86_64-pc-linux-gnu/libstdc++-v3/libsupc++/.libs -B/home/marxin/bin/gcc/x86_64-pc-linux-gnu/bin/ -B/home/marxin/bin/gcc/x86_64-pc-linux-gnu/lib/ -isystem /home/marxin/bin/gcc/x86_64-pc-linux-gnu/include -isystem /home/marxin/bin/gcc/x86_64-pc-linux-gnu/sys-include -D_GNU_SOURCE -D_DEBUG -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -DHAVE_RPC_XDR_H=0 -DHAVE_TIRPC_RPC_XDR_H=0 -I. -I/home/marxin/Programming/gcc/libsanitizer/sanitizer_common -I.. -I /home/marxin/Programming/gcc/libsanitizer/include -I /home/marxin/Programming/gcc/libsanitizer -isystem /home/marxin/Programming/gcc/libsanitizer/include/system -Wall -W -Wno-unused-parameter -Wwrite-strings -pedantic -Wno-long-long -fPIC -fno-builtin -fno-exceptions -fno-rtti -fomit-frame-pointer -funwind-tables -fvisibility=hidden -Wno-variadic-macros -I../../libstdc++-v3/include -I../../libstdc++-v3/include/x86_64-pc-linux-gnu -I/home/marxin/Programming/gcc/libsanitizer/../libstdc++-v3/libsupc++ -std=gnu++14 -fcf-protection -mshstk -DSANITIZER_LIBBACKTRACE -DSANITIZER_CP_DEMANGLE -I /home/marxin/Programming/gcc/libsanitizer/../libbacktrace -I ../libbacktrace -I /home/marxin/Programming/gcc/libsanitizer/../include -include /home/marxin/Programming/gcc/libsanitizer/libbacktrace/backtrace-rename.h -g -O2 -D_GNU_SOURCE -MT sanitizer_linux_libcdep.lo -MD -MP -MF .deps/sanitizer_linux_libcdep.Tpo -c /home/marxin/Programming/gcc/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp -fPIC -DPIC -o .libs/sanitizer_linux_libcdep.o
>
> Can you please show full command line? And please attach a pre-processed source file.
> Thanks,
> Martin
The problem is -mx32 where size_t == unsigned int, not unsigned long int.
--
H.J.
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH] libsanitizer: merge from master
2021-05-13 20:01 ` H.J. Lu
@ 2021-05-13 20:11 ` H.J. Lu
2021-05-14 1:26 ` [PATCH] libsanitizer: cherry-pick from upstream H.J. Lu
0 siblings, 1 reply; 17+ messages in thread
From: H.J. Lu @ 2021-05-13 20:11 UTC (permalink / raw)
To: Martin Liška; +Cc: GCC Patches
On Thu, May 13, 2021 at 1:01 PM H.J. Lu <hjl.tools@gmail.com> wrote:
>
> On Thu, May 13, 2021 at 10:27 AM Martin Liška <mliska@suse.cz> wrote:
> >
> > On 5/13/21 5:54 PM, H.J. Lu wrote:
> > > On Thu, May 13, 2021 at 09:28:01AM +0200, Martin Liška wrote:
> > >> I'm planning to do merge from master twice a year.
> > >> This merge was tested on x86_64-linux-gnu and ppc64le-linux-gnu
> > >> and survives regression tests.
> > >>
> > >> Pushed to master.
> > >> Thanks,
> > >> Martin
> > >>
> > >> Merged revision: f58e0513dd95944b81ce7a6e7b49ba656de7d75f
> > >
> > > On Linux/x86-64, I got
> > >
> > > ../../../../../src-master/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp: In function ??void __sanitizer::InitTlsSize()??:
> > > ../../../../../src-master/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp:209:55: error: invalid conversion from ??__sanitizer::uptr*?? {aka ??long unsigned int*??} to ??size_t*?? {aka ??unsigned int*??} [-fpermissive]
> > > 209 | ((void (*)(size_t *, size_t *))get_tls_static_info)(&g_tls_size, &tls_align);
> > > | ^~~~~~~~~~~
> > > | |
> > > | __sanitizer::uptr* {aka long unsigned int*}
> > >
> > >
> > > H.J.
> > >
> >
> > Hm, I can't reproduce it:
> >
> > /dev/shm/objdir/./gcc/xgcc -shared-libgcc -B/dev/shm/objdir/./gcc -nostdinc++ -L/dev/shm/objdir/x86_64-pc-linux-gnu/libstdc++-v3/src -L/dev/shm/objdir/x86_64-pc-linux-gnu/libstdc++-v3/src/.libs -L/dev/shm/objdir/x86_64-pc-linux-gnu/libstdc++-v3/libsupc++/.libs -B/home/marxin/bin/gcc/x86_64-pc-linux-gnu/bin/ -B/home/marxin/bin/gcc/x86_64-pc-linux-gnu/lib/ -isystem /home/marxin/bin/gcc/x86_64-pc-linux-gnu/include -isystem /home/marxin/bin/gcc/x86_64-pc-linux-gnu/sys-include -D_GNU_SOURCE -D_DEBUG -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -DHAVE_RPC_XDR_H=0 -DHAVE_TIRPC_RPC_XDR_H=0 -I. -I/home/marxin/Programming/gcc/libsanitizer/sanitizer_common -I.. -I /home/marxin/Programming/gcc/libsanitizer/include -I /home/marxin/Programming/gcc/libsanitizer -isystem /home/marxin/Programming/gcc/libsanitizer/include/system -Wall -W -Wno-unused-parameter -Wwrite-strings -pedantic -Wno-long-long -fPIC -fno-builtin -fno-exceptions -fno-rtti -fomit-frame-pointer -funwind-tables -fvisibility=hidden -Wno-variadic-macros -I../../libstdc++-v3/include -I../../libstdc++-v3/include/x86_64-pc-linux-gnu -I/home/marxin/Programming/gcc/libsanitizer/../libstdc++-v3/libsupc++ -std=gnu++14 -fcf-protection -mshstk -DSANITIZER_LIBBACKTRACE -DSANITIZER_CP_DEMANGLE -I /home/marxin/Programming/gcc/libsanitizer/../libbacktrace -I ../libbacktrace -I /home/marxin/Programming/gcc/libsanitizer/../include -include /home/marxin/Programming/gcc/libsanitizer/libbacktrace/backtrace-rename.h -g -O2 -D_GNU_SOURCE -MT sanitizer_linux_libcdep.lo -MD -MP -MF .deps/sanitizer_linux_libcdep.Tpo -c /home/marxin/Programming/gcc/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp -fPIC -DPIC -o .libs/sanitizer_linux_libcdep.o
> >
> > Can you please show full command line? And please attach a pre-processed source file.
> > Thanks,
> > Martin
>
> The problem is -mx32 where size_t == unsigned int, not unsigned long int.
>
I am testing this patch:
diff --git a/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp
b/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp
index da19d3d2ceb..4f9577a97e2 100644
--- a/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp
@@ -197,7 +197,7 @@ __attribute__((unused)) static bool
GetLibcVersion(int *major, int *minor,
__attribute__((unused)) static int g_use_dlpi_tls_data;
#if SANITIZER_GLIBC && !SANITIZER_GO
-__attribute__((unused)) static uptr g_tls_size;
+__attribute__((unused)) static size_t g_tls_size;
void InitTlsSize() {
int major, minor, patch;
g_use_dlpi_tls_data =
--
H.J.
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH] libsanitizer: cherry-pick from upstream
2021-05-13 20:11 ` H.J. Lu
@ 2021-05-14 1:26 ` H.J. Lu
0 siblings, 0 replies; 17+ messages in thread
From: H.J. Lu @ 2021-05-14 1:26 UTC (permalink / raw)
To: Martin Liška; +Cc: GCC Patches
[-- Attachment #1: Type: text/plain, Size: 4306 bytes --]
On Thu, May 13, 2021 at 1:11 PM H.J. Lu <hjl.tools@gmail.com> wrote:
>
> On Thu, May 13, 2021 at 1:01 PM H.J. Lu <hjl.tools@gmail.com> wrote:
> >
> > On Thu, May 13, 2021 at 10:27 AM Martin Liška <mliska@suse.cz> wrote:
> > >
> > > On 5/13/21 5:54 PM, H.J. Lu wrote:
> > > > On Thu, May 13, 2021 at 09:28:01AM +0200, Martin Liška wrote:
> > > >> I'm planning to do merge from master twice a year.
> > > >> This merge was tested on x86_64-linux-gnu and ppc64le-linux-gnu
> > > >> and survives regression tests.
> > > >>
> > > >> Pushed to master.
> > > >> Thanks,
> > > >> Martin
> > > >>
> > > >> Merged revision: f58e0513dd95944b81ce7a6e7b49ba656de7d75f
> > > >
> > > > On Linux/x86-64, I got
> > > >
> > > > ../../../../../src-master/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp: In function ??void __sanitizer::InitTlsSize()??:
> > > > ../../../../../src-master/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp:209:55: error: invalid conversion from ??__sanitizer::uptr*?? {aka ??long unsigned int*??} to ??size_t*?? {aka ??unsigned int*??} [-fpermissive]
> > > > 209 | ((void (*)(size_t *, size_t *))get_tls_static_info)(&g_tls_size, &tls_align);
> > > > | ^~~~~~~~~~~
> > > > | |
> > > > | __sanitizer::uptr* {aka long unsigned int*}
> > > >
> > > >
> > > > H.J.
> > > >
> > >
> > > Hm, I can't reproduce it:
> > >
> > > /dev/shm/objdir/./gcc/xgcc -shared-libgcc -B/dev/shm/objdir/./gcc -nostdinc++ -L/dev/shm/objdir/x86_64-pc-linux-gnu/libstdc++-v3/src -L/dev/shm/objdir/x86_64-pc-linux-gnu/libstdc++-v3/src/.libs -L/dev/shm/objdir/x86_64-pc-linux-gnu/libstdc++-v3/libsupc++/.libs -B/home/marxin/bin/gcc/x86_64-pc-linux-gnu/bin/ -B/home/marxin/bin/gcc/x86_64-pc-linux-gnu/lib/ -isystem /home/marxin/bin/gcc/x86_64-pc-linux-gnu/include -isystem /home/marxin/bin/gcc/x86_64-pc-linux-gnu/sys-include -D_GNU_SOURCE -D_DEBUG -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -DHAVE_RPC_XDR_H=0 -DHAVE_TIRPC_RPC_XDR_H=0 -I. -I/home/marxin/Programming/gcc/libsanitizer/sanitizer_common -I.. -I /home/marxin/Programming/gcc/libsanitizer/include -I /home/marxin/Programming/gcc/libsanitizer -isystem /home/marxin/Programming/gcc/libsanitizer/include/system -Wall -W -Wno-unused-parameter -Wwrite-strings -pedantic -Wno-long-long -fPIC -fno-builtin -fno-exceptions -fno-rtti -fomit-frame-pointer -funwind-tables -fvisibility=hidden -Wno-variadic-macros -I../../libstdc++-v3/include -I../../libstdc++-v3/include/x86_64-pc-linux-gnu -I/home/marxin/Programming/gcc/libsanitizer/../libstdc++-v3/libsupc++ -std=gnu++14 -fcf-protection -mshstk -DSANITIZER_LIBBACKTRACE -DSANITIZER_CP_DEMANGLE -I /home/marxin/Programming/gcc/libsanitizer/../libbacktrace -I ../libbacktrace -I /home/marxin/Programming/gcc/libsanitizer/../include -include /home/marxin/Programming/gcc/libsanitizer/libbacktrace/backtrace-rename.h -g -O2 -D_GNU_SOURCE -MT sanitizer_linux_libcdep.lo -MD -MP -MF .deps/sanitizer_linux_libcdep.Tpo -c /home/marxin/Programming/gcc/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp -fPIC -DPIC -o .libs/sanitizer_linux_libcdep.o
> > >
> > > Can you please show full command line? And please attach a pre-processed source file.
> > > Thanks,
> > > Martin
> >
> > The problem is -mx32 where size_t == unsigned int, not unsigned long int.
> >
>
> I am testing this patch:
>
> diff --git a/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp
> b/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp
> index da19d3d2ceb..4f9577a97e2 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp
> @@ -197,7 +197,7 @@ __attribute__((unused)) static bool
> GetLibcVersion(int *major, int *minor,
> __attribute__((unused)) static int g_use_dlpi_tls_data;
>
> #if SANITIZER_GLIBC && !SANITIZER_GO
> -__attribute__((unused)) static uptr g_tls_size;
> +__attribute__((unused)) static size_t g_tls_size;
> void InitTlsSize() {
> int major, minor, patch;
> g_use_dlpi_tls_data =
This is what I checked in.
--
H.J.
[-- Attachment #2: 0001-libsanitizer-cherry-pick-from-upstream.patch --]
[-- Type: text/x-patch, Size: 1083 bytes --]
From f3b1516d9dfd969d7cc1ca6f26dec13478a1c458 Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Thu, 13 May 2021 18:23:55 -0700
Subject: [PATCH] libsanitizer: cherry-pick from upstream
cherry-pick:
72797dedb720 [sanitizer] Use size_t on g_tls_size to fix build on x32
---
libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp
index da19d3d2ceb..4f9577a97e2 100644
--- a/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp
@@ -197,7 +197,7 @@ __attribute__((unused)) static bool GetLibcVersion(int *major, int *minor,
__attribute__((unused)) static int g_use_dlpi_tls_data;
#if SANITIZER_GLIBC && !SANITIZER_GO
-__attribute__((unused)) static uptr g_tls_size;
+__attribute__((unused)) static size_t g_tls_size;
void InitTlsSize() {
int major, minor, patch;
g_use_dlpi_tls_data =
--
2.31.1
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH] libsanitizer: merge from master
2021-05-13 7:28 [PATCH] libsanitizer: merge from master Martin Liška
2021-05-13 15:54 ` H.J. Lu
@ 2021-06-04 7:32 ` Hongtao Liu
2021-06-04 7:36 ` Martin Liška
1 sibling, 1 reply; 17+ messages in thread
From: Hongtao Liu @ 2021-06-04 7:32 UTC (permalink / raw)
To: Martin Liška; +Cc: GCC Patches
Hi:
I'm currently working on support hwasan with Intel LAM, i found
there's gap between gcc libsanitizer and corresponding llvm
compiler-rt, so could you help to sync from llvm to gcc libsanitizer.
Or is there's any instructions i can follow to sync it myself?
On Thu, May 13, 2021 at 3:50 PM Martin Liška <mliska@suse.cz> wrote:
>
> I'm planning to do merge from master twice a year.
> This merge was tested on x86_64-linux-gnu and ppc64le-linux-gnu
> and survives regression tests.
>
> Pushed to master.
> Thanks,
> Martin
>
> Merged revision: f58e0513dd95944b81ce7a6e7b49ba656de7d75f
> ---
> libsanitizer/MERGE | 2 +-
> libsanitizer/asan/asan_allocator.cpp | 32 +-
> libsanitizer/asan/asan_descriptions.cpp | 19 +-
> libsanitizer/asan/asan_descriptions.h | 13 +-
> libsanitizer/asan/asan_errors.cpp | 7 +-
> libsanitizer/asan/asan_fake_stack.cpp | 2 +-
> libsanitizer/asan/asan_fuchsia.cpp | 2 +-
> libsanitizer/asan/asan_globals.cpp | 19 +
> libsanitizer/asan/asan_interceptors.cpp | 41 +-
> libsanitizer/asan/asan_interceptors.h | 21 +-
> libsanitizer/asan/asan_linux.cpp | 3 +-
> libsanitizer/asan/asan_mapping.h | 25 +-
> libsanitizer/asan/asan_new_delete.cpp | 2 +-
> libsanitizer/asan/asan_poisoning.cpp | 2 +-
> libsanitizer/asan/asan_posix.cpp | 2 +-
> libsanitizer/asan/asan_rtl.cpp | 20 +-
> libsanitizer/asan/asan_stack.h | 9 -
> libsanitizer/asan/asan_thread.cpp | 51 +-
> libsanitizer/asan/asan_thread.h | 6 +-
> libsanitizer/asan/asan_win.cpp | 2 +-
> libsanitizer/builtins/assembly.h | 98 +++-
> libsanitizer/hwasan/hwasan.cpp | 19 +-
> libsanitizer/hwasan/hwasan.h | 41 +-
> libsanitizer/hwasan/hwasan_allocator.cpp | 28 +-
> libsanitizer/hwasan/hwasan_allocator.h | 19 +-
> libsanitizer/hwasan/hwasan_checks.h | 5 +-
> libsanitizer/hwasan/hwasan_dynamic_shadow.cpp | 16 +-
> libsanitizer/hwasan/hwasan_flags.h | 2 +
> libsanitizer/hwasan/hwasan_flags.inc | 9 +
> libsanitizer/hwasan/hwasan_interceptors.cpp | 3 +-
> .../hwasan/hwasan_interceptors_vfork.S | 3 +
> .../hwasan/hwasan_interface_internal.h | 3 +
> libsanitizer/hwasan/hwasan_linux.cpp | 41 +-
> libsanitizer/hwasan/hwasan_mapping.h | 2 +
> libsanitizer/hwasan/hwasan_memintrinsics.cpp | 4 +-
> libsanitizer/hwasan/hwasan_new_delete.cpp | 39 ++
> libsanitizer/hwasan/hwasan_report.cpp | 26 +-
> libsanitizer/hwasan/hwasan_setjmp.S | 6 +
> .../hwasan/hwasan_tag_mismatch_aarch64.S | 6 +
> libsanitizer/hwasan/hwasan_thread.cpp | 15 +-
> libsanitizer/hwasan/hwasan_thread.h | 4 +-
> libsanitizer/hwasan/hwasan_thread_list.h | 90 ++--
> .../include/sanitizer/common_interface_defs.h | 3 +
> .../include/sanitizer/dfsan_interface.h | 16 +
> .../include/sanitizer/hwasan_interface.h | 3 +
> .../include/sanitizer/memprof_interface.h | 5 +
> .../include/sanitizer/tsan_interface.h | 17 +-
> .../include/sanitizer/tsan_interface_atomic.h | 2 +-
> .../interception/interception_linux.cpp | 6 +-
> .../interception/interception_linux.h | 6 +-
> .../interception/interception_win.cpp | 6 +-
> libsanitizer/lsan/lsan_allocator.cpp | 26 +-
> libsanitizer/lsan/lsan_allocator.h | 2 +-
> libsanitizer/lsan/lsan_common.cpp | 234 ++++++---
> libsanitizer/lsan/lsan_common.h | 9 +-
> libsanitizer/lsan/lsan_common_fuchsia.cpp | 4 +-
> libsanitizer/lsan/lsan_fuchsia.h | 2 +-
> libsanitizer/lsan/lsan_interceptors.cpp | 2 +-
> libsanitizer/lsan/lsan_posix.cpp | 6 +-
> libsanitizer/lsan/lsan_thread.cpp | 2 +-
> .../sanitizer_allocator_combined.h | 4 +-
> .../sanitizer_allocator_primary32.h | 3 +-
> .../sanitizer_allocator_primary64.h | 93 +++-
> .../sanitizer_allocator_size_class_map.h | 2 +-
> .../sanitizer_atomic_clang_mips.h | 8 +-
> .../sanitizer_chained_origin_depot.cpp | 108 +++++
> .../sanitizer_chained_origin_depot.h | 88 ++++
> .../sanitizer_common/sanitizer_common.cpp | 10 +-
> .../sanitizer_common/sanitizer_common.h | 82 +++-
> .../sanitizer_common_interceptors.inc | 19 +-
> .../sanitizer_common_interceptors_ioctl.inc | 6 +-
> ...er_common_interceptors_vfork_aarch64.inc.S | 5 +
> .../sanitizer_common_interface.inc | 1 +
> .../sanitizer_common_libcdep.cpp | 7 +-
> .../sanitizer_common/sanitizer_file.cpp | 13 +
> .../sanitizer_common/sanitizer_file.h | 1 +
> .../sanitizer_common/sanitizer_flags.cpp | 7 +
> .../sanitizer_common/sanitizer_flags.inc | 2 +
> .../sanitizer_common/sanitizer_fuchsia.cpp | 72 +--
> .../sanitizer_interface_internal.h | 4 +
> .../sanitizer_internal_defs.h | 3 +
> .../sanitizer_common/sanitizer_libignore.cpp | 2 +-
> .../sanitizer_common/sanitizer_linux.cpp | 72 +--
> .../sanitizer_common/sanitizer_linux.h | 3 +-
> .../sanitizer_linux_libcdep.cpp | 447 ++++++++++--------
> .../sanitizer_local_address_space_view.h | 2 +-
> .../sanitizer_common/sanitizer_mac.cpp | 141 +++++-
> libsanitizer/sanitizer_common/sanitizer_mac.h | 37 --
> .../sanitizer_common/sanitizer_malloc_mac.inc | 6 +-
> .../sanitizer_common/sanitizer_netbsd.cpp | 6 +
> .../sanitizer_common/sanitizer_platform.h | 27 +-
> .../sanitizer_platform_interceptors.h | 113 +++--
> .../sanitizer_platform_limits_freebsd.cpp | 3 +
> .../sanitizer_platform_limits_linux.cpp | 7 +-
> .../sanitizer_platform_limits_posix.cpp | 85 ++--
> .../sanitizer_platform_limits_posix.h | 4 +-
> .../sanitizer_common/sanitizer_posix.cpp | 4 +-
> .../sanitizer_common/sanitizer_posix.h | 4 +
> .../sanitizer_posix_libcdep.cpp | 2 +-
> .../sanitizer_common/sanitizer_printf.cpp | 57 ++-
> .../sanitizer_procmaps_common.cpp | 2 +-
> .../sanitizer_procmaps_mac.cpp | 4 +-
> .../sanitizer_procmaps_solaris.cpp | 4 +-
> .../sanitizer_common/sanitizer_ptrauth.h | 20 +-
> .../sanitizer_common/sanitizer_stackdepot.cpp | 3 +-
> .../sanitizer_common/sanitizer_stacktrace.cpp | 20 +-
> .../sanitizer_common/sanitizer_stacktrace.h | 2 -
> .../sanitizer_stacktrace_libcdep.cpp | 8 +-
> .../sanitizer_stoptheworld_linux_libcdep.cpp | 5 +
> .../sanitizer_suppressions.cpp | 4 +-
> .../sanitizer_symbolizer_libcdep.cpp | 2 +-
> .../sanitizer_symbolizer_markup.cpp | 4 +
> .../sanitizer_symbolizer_posix_libcdep.cpp | 11 +-
> .../sanitizer_symbolizer_report.cpp | 6 +-
> .../sanitizer_symbolizer_win.cpp | 18 +-
> .../sanitizer_termination.cpp | 33 +-
> .../sanitizer_thread_registry.cpp | 14 +-
> .../sanitizer_thread_registry.h | 7 +-
> .../sanitizer_tls_get_addr.cpp | 79 ++--
> .../sanitizer_common/sanitizer_tls_get_addr.h | 21 +-
> .../sanitizer_common/sanitizer_unwind_win.cpp | 7 +
> .../sanitizer_common/sanitizer_win.cpp | 84 ++--
> libsanitizer/tsan/tsan_clock.cpp | 37 +-
> libsanitizer/tsan/tsan_clock.h | 16 +-
> libsanitizer/tsan/tsan_defs.h | 2 -
> libsanitizer/tsan/tsan_dense_alloc.h | 32 +-
> libsanitizer/tsan/tsan_external.cpp | 4 +-
> libsanitizer/tsan/tsan_interceptors_mac.cpp | 1 +
> libsanitizer/tsan/tsan_interceptors_posix.cpp | 149 ++++--
> libsanitizer/tsan/tsan_interface.cpp | 8 +-
> libsanitizer/tsan/tsan_interface.h | 9 +-
> libsanitizer/tsan/tsan_interface_inl.h | 22 +-
> libsanitizer/tsan/tsan_mman.cpp | 2 +-
> libsanitizer/tsan/tsan_platform.h | 121 ++++-
> libsanitizer/tsan/tsan_platform_linux.cpp | 23 +-
> libsanitizer/tsan/tsan_platform_mac.cpp | 9 +-
> libsanitizer/tsan/tsan_platform_posix.cpp | 2 +-
> libsanitizer/tsan/tsan_report.cpp | 14 +-
> libsanitizer/tsan/tsan_rtl.cpp | 129 +++--
> libsanitizer/tsan/tsan_rtl.h | 11 +-
> libsanitizer/tsan/tsan_rtl_mutex.cpp | 25 +-
> libsanitizer/tsan/tsan_rtl_ppc64.S | 1 -
> libsanitizer/tsan/tsan_rtl_report.cpp | 56 ++-
> libsanitizer/tsan/tsan_rtl_thread.cpp | 13 +-
> libsanitizer/tsan/tsan_sync.cpp | 4 +-
> libsanitizer/tsan/tsan_sync.h | 8 +-
> libsanitizer/ubsan/ubsan_diag.cpp | 8 +-
> libsanitizer/ubsan/ubsan_flags.cpp | 1 -
> libsanitizer/ubsan/ubsan_handlers.cpp | 15 -
> libsanitizer/ubsan/ubsan_handlers.h | 8 -
> libsanitizer/ubsan/ubsan_init.cpp | 9 +
> libsanitizer/ubsan/ubsan_monitor.cpp | 6 +-
> libsanitizer/ubsan/ubsan_platform.h | 4 +-
> 153 files changed, 2538 insertions(+), 1239 deletions(-)
> create mode 100644 libsanitizer/sanitizer_common/sanitizer_chained_origin_depot.cpp
> create mode 100644 libsanitizer/sanitizer_common/sanitizer_chained_origin_depot.h
>
> diff --git a/libsanitizer/MERGE b/libsanitizer/MERGE
> index 0fb64a9567c..c4731d0866c 100644
> --- a/libsanitizer/MERGE
> +++ b/libsanitizer/MERGE
> @@ -1,4 +1,4 @@
> -6e7dd1e3e1170080b76b5dcc5716bdd974343233
> +f58e0513dd95944b81ce7a6e7b49ba656de7d75f
>
> The first line of this file holds the git revision number of the
> last merge done from the master library sources.
> diff --git a/libsanitizer/asan/asan_allocator.cpp b/libsanitizer/asan/asan_allocator.cpp
> index 58b496a3ca4..7c8bb504332 100644
> --- a/libsanitizer/asan/asan_allocator.cpp
> +++ b/libsanitizer/asan/asan_allocator.cpp
> @@ -476,7 +476,7 @@ struct Allocator {
> return false;
> if (m->Beg() != addr) return false;
> AsanThread *t = GetCurrentThread();
> - m->SetAllocContext(t ? t->tid() : 0, StackDepotPut(*stack));
> + m->SetAllocContext(t ? t->tid() : kMainTid, StackDepotPut(*stack));
> return true;
> }
>
> @@ -570,7 +570,7 @@ struct Allocator {
> m->SetUsedSize(size);
> m->user_requested_alignment_log = user_requested_alignment_log;
>
> - m->SetAllocContext(t ? t->tid() : 0, StackDepotPut(*stack));
> + m->SetAllocContext(t ? t->tid() : kMainTid, StackDepotPut(*stack));
>
> uptr size_rounded_down_to_granularity =
> RoundDownTo(size, SHADOW_GRANULARITY);
> @@ -1183,6 +1183,34 @@ IgnoreObjectResult IgnoreObjectLocked(const void *p) {
> m->lsan_tag = __lsan::kIgnored;
> return kIgnoreObjectSuccess;
> }
> +
> +void GetAdditionalThreadContextPtrs(ThreadContextBase *tctx, void *ptrs) {
> + // Look for the arg pointer of threads that have been created or are running.
> + // This is necessary to prevent false positive leaks due to the AsanThread
> + // holding the only live reference to a heap object. This can happen because
> + // the `pthread_create()` interceptor doesn't wait for the child thread to
> + // start before returning and thus loosing the the only live reference to the
> + // heap object on the stack.
> +
> + __asan::AsanThreadContext *atctx =
> + reinterpret_cast<__asan::AsanThreadContext *>(tctx);
> + __asan::AsanThread *asan_thread = atctx->thread;
> +
> + // Note ThreadStatusRunning is required because there is a small window where
> + // the thread status switches to `ThreadStatusRunning` but the `arg` pointer
> + // still isn't on the stack yet.
> + if (atctx->status != ThreadStatusCreated &&
> + atctx->status != ThreadStatusRunning)
> + return;
> +
> + uptr thread_arg = reinterpret_cast<uptr>(asan_thread->get_arg());
> + if (!thread_arg)
> + return;
> +
> + auto ptrsVec = reinterpret_cast<InternalMmapVector<uptr> *>(ptrs);
> + ptrsVec->push_back(thread_arg);
> +}
> +
> } // namespace __lsan
>
> // ---------------------- Interface ---------------- {{{1
> diff --git a/libsanitizer/asan/asan_descriptions.cpp b/libsanitizer/asan/asan_descriptions.cpp
> index 153c874a4e7..2ba8a02f841 100644
> --- a/libsanitizer/asan/asan_descriptions.cpp
> +++ b/libsanitizer/asan/asan_descriptions.cpp
> @@ -44,11 +44,11 @@ void DescribeThread(AsanThreadContext *context) {
> CHECK(context);
> asanThreadRegistry().CheckLocked();
> // No need to announce the main thread.
> - if (context->tid == 0 || context->announced) {
> + if (context->tid == kMainTid || context->announced) {
> return;
> }
> context->announced = true;
> - InternalScopedString str(1024);
> + InternalScopedString str;
> str.append("Thread %s", AsanThreadIdAndName(context).c_str());
> if (context->parent_tid == kInvalidTid) {
> str.append(" created by unknown thread\n");
> @@ -77,7 +77,6 @@ static bool GetShadowKind(uptr addr, ShadowKind *shadow_kind) {
> } else if (AddrIsInLowShadow(addr)) {
> *shadow_kind = kShadowKindLow;
> } else {
> - CHECK(0 && "Address is not in memory and not in shadow?");
> return false;
> }
> return true;
> @@ -126,7 +125,7 @@ static void GetAccessToHeapChunkInformation(ChunkAccess *descr,
>
> static void PrintHeapChunkAccess(uptr addr, const ChunkAccess &descr) {
> Decorator d;
> - InternalScopedString str(4096);
> + InternalScopedString str;
> str.append("%s", d.Location());
> switch (descr.access_type) {
> case kAccessTypeLeft:
> @@ -243,7 +242,7 @@ static void PrintAccessAndVarIntersection(const StackVarDescr &var, uptr addr,
> else if (addr >= prev_var_end && addr - prev_var_end >= var.beg - addr_end)
> pos_descr = "underflows";
> }
> - InternalScopedString str(1024);
> + InternalScopedString str;
> str.append(" [%zd, %zd)", var.beg, var_end);
> // Render variable name.
> str.append(" '");
> @@ -276,7 +275,7 @@ bool DescribeAddressIfStack(uptr addr, uptr access_size) {
> // Global descriptions
> static void DescribeAddressRelativeToGlobal(uptr addr, uptr access_size,
> const __asan_global &g) {
> - InternalScopedString str(4096);
> + InternalScopedString str;
> Decorator d;
> str.append("%s", d.Location());
> if (addr < g.beg) {
> @@ -464,7 +463,13 @@ AddressDescription::AddressDescription(uptr addr, uptr access_size,
> return;
> }
> data.kind = kAddressKindWild;
> - addr = 0;
> + data.wild.addr = addr;
> + data.wild.access_size = access_size;
> +}
> +
> +void WildAddressDescription::Print() const {
> + Printf("Address %p is a wild pointer inside of access range of size %p.\n",
> + addr, access_size);
> }
>
> void PrintAddressDescription(uptr addr, uptr access_size,
> diff --git a/libsanitizer/asan/asan_descriptions.h b/libsanitizer/asan/asan_descriptions.h
> index ee0e2061559..650e2eb9173 100644
> --- a/libsanitizer/asan/asan_descriptions.h
> +++ b/libsanitizer/asan/asan_descriptions.h
> @@ -146,6 +146,13 @@ struct StackAddressDescription {
> bool GetStackAddressInformation(uptr addr, uptr access_size,
> StackAddressDescription *descr);
>
> +struct WildAddressDescription {
> + uptr addr;
> + uptr access_size;
> +
> + void Print() const;
> +};
> +
> struct GlobalAddressDescription {
> uptr addr;
> // Assume address is close to at most four globals.
> @@ -193,7 +200,7 @@ class AddressDescription {
> HeapAddressDescription heap;
> StackAddressDescription stack;
> GlobalAddressDescription global;
> - uptr addr;
> + WildAddressDescription wild;
> };
> };
>
> @@ -211,7 +218,7 @@ class AddressDescription {
> uptr Address() const {
> switch (data.kind) {
> case kAddressKindWild:
> - return data.addr;
> + return data.wild.addr;
> case kAddressKindShadow:
> return data.shadow.addr;
> case kAddressKindHeap:
> @@ -226,7 +233,7 @@ class AddressDescription {
> void Print(const char *bug_descr = nullptr) const {
> switch (data.kind) {
> case kAddressKindWild:
> - Printf("Address %p is a wild pointer.\n", data.addr);
> + data.wild.Print();
> return;
> case kAddressKindShadow:
> return data.shadow.Print();
> diff --git a/libsanitizer/asan/asan_errors.cpp b/libsanitizer/asan/asan_errors.cpp
> index 541c6e0353b..e68e6971f96 100644
> --- a/libsanitizer/asan/asan_errors.cpp
> +++ b/libsanitizer/asan/asan_errors.cpp
> @@ -343,7 +343,8 @@ void ErrorODRViolation::Print() {
> Report("ERROR: AddressSanitizer: %s (%p):\n", scariness.GetDescription(),
> global1.beg);
> Printf("%s", d.Default());
> - InternalScopedString g1_loc(256), g2_loc(256);
> + InternalScopedString g1_loc;
> + InternalScopedString g2_loc;
> PrintGlobalLocation(&g1_loc, global1);
> PrintGlobalLocation(&g2_loc, global2);
> Printf(" [1] size=%zd '%s' %s\n", global1.size,
> @@ -360,7 +361,7 @@ void ErrorODRViolation::Print() {
> Report(
> "HINT: if you don't care about these errors you may set "
> "ASAN_OPTIONS=detect_odr_violation=0\n");
> - InternalScopedString error_msg(256);
> + InternalScopedString error_msg;
> error_msg.append("%s: global '%s' at %s", scariness.GetDescription(),
> MaybeDemangleGlobalName(global1.name), g1_loc.data());
> ReportErrorSummary(error_msg.data());
> @@ -554,7 +555,7 @@ static void PrintShadowMemoryForAddress(uptr addr) {
> uptr shadow_addr = MemToShadow(addr);
> const uptr n_bytes_per_row = 16;
> uptr aligned_shadow = shadow_addr & ~(n_bytes_per_row - 1);
> - InternalScopedString str(4096 * 8);
> + InternalScopedString str;
> str.append("Shadow bytes around the buggy address:\n");
> for (int i = -5; i <= 5; i++) {
> uptr row_shadow_addr = aligned_shadow + i * n_bytes_per_row;
> diff --git a/libsanitizer/asan/asan_fake_stack.cpp b/libsanitizer/asan/asan_fake_stack.cpp
> index 295e6debc96..1f873fec7d7 100644
> --- a/libsanitizer/asan/asan_fake_stack.cpp
> +++ b/libsanitizer/asan/asan_fake_stack.cpp
> @@ -65,7 +65,7 @@ FakeStack *FakeStack::Create(uptr stack_size_log) {
> void FakeStack::Destroy(int tid) {
> PoisonAll(0);
> if (Verbosity() >= 2) {
> - InternalScopedString str(kNumberOfSizeClasses * 50);
> + InternalScopedString str;
> for (uptr class_id = 0; class_id < kNumberOfSizeClasses; class_id++)
> str.append("%zd: %zd/%zd; ", class_id, hint_position_[class_id],
> NumberOfFrames(stack_size_log(), class_id));
> diff --git a/libsanitizer/asan/asan_fuchsia.cpp b/libsanitizer/asan/asan_fuchsia.cpp
> index 6c61344f87c..b0c7255144a 100644
> --- a/libsanitizer/asan/asan_fuchsia.cpp
> +++ b/libsanitizer/asan/asan_fuchsia.cpp
> @@ -81,7 +81,7 @@ void AsanTSDInit(void (*destructor)(void *tsd)) {
> void PlatformTSDDtor(void *tsd) { UNREACHABLE(__func__); }
>
> static inline size_t AsanThreadMmapSize() {
> - return RoundUpTo(sizeof(AsanThread), PAGE_SIZE);
> + return RoundUpTo(sizeof(AsanThread), _zx_system_get_page_size());
> }
>
> struct AsanThread::InitOptions {
> diff --git a/libsanitizer/asan/asan_globals.cpp b/libsanitizer/asan/asan_globals.cpp
> index e045c31cd1c..9d7dbc6f264 100644
> --- a/libsanitizer/asan/asan_globals.cpp
> +++ b/libsanitizer/asan/asan_globals.cpp
> @@ -154,6 +154,23 @@ static void CheckODRViolationViaIndicator(const Global *g) {
> }
> }
>
> +// Check ODR violation for given global G by checking if it's already poisoned.
> +// We use this method in case compiler doesn't use private aliases for global
> +// variables.
> +static void CheckODRViolationViaPoisoning(const Global *g) {
> + if (__asan_region_is_poisoned(g->beg, g->size_with_redzone)) {
> + // This check may not be enough: if the first global is much larger
> + // the entire redzone of the second global may be within the first global.
> + for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) {
> + if (g->beg == l->g->beg &&
> + (flags()->detect_odr_violation >= 2 || g->size != l->g->size) &&
> + !IsODRViolationSuppressed(g->name))
> + ReportODRViolation(g, FindRegistrationSite(g),
> + l->g, FindRegistrationSite(l->g));
> + }
> + }
> +}
> +
> // Clang provides two different ways for global variables protection:
> // it can poison the global itself or its private alias. In former
> // case we may poison same symbol multiple times, that can help us to
> @@ -199,6 +216,8 @@ static void RegisterGlobal(const Global *g) {
> // where two globals with the same name are defined in different modules.
> if (UseODRIndicator(g))
> CheckODRViolationViaIndicator(g);
> + else
> + CheckODRViolationViaPoisoning(g);
> }
> if (CanPoisonMemory())
> PoisonRedZones(*g);
> diff --git a/libsanitizer/asan/asan_interceptors.cpp b/libsanitizer/asan/asan_interceptors.cpp
> index 4e68b3b0b47..9db7db89fa1 100644
> --- a/libsanitizer/asan/asan_interceptors.cpp
> +++ b/libsanitizer/asan/asan_interceptors.cpp
> @@ -191,20 +191,11 @@ DECLARE_REAL_AND_INTERCEPTOR(void, free, void *)
> #include "sanitizer_common/sanitizer_common_syscalls.inc"
> #include "sanitizer_common/sanitizer_syscalls_netbsd.inc"
>
> -struct ThreadStartParam {
> - atomic_uintptr_t t;
> - atomic_uintptr_t is_registered;
> -};
> -
> #if ASAN_INTERCEPT_PTHREAD_CREATE
> static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) {
> - ThreadStartParam *param = reinterpret_cast<ThreadStartParam *>(arg);
> - AsanThread *t = nullptr;
> - while ((t = reinterpret_cast<AsanThread *>(
> - atomic_load(¶m->t, memory_order_acquire))) == nullptr)
> - internal_sched_yield();
> + AsanThread *t = (AsanThread *)arg;
> SetCurrentThread(t);
> - return t->ThreadStart(GetTid(), ¶m->is_registered);
> + return t->ThreadStart(GetTid());
> }
>
> INTERCEPTOR(int, pthread_create, void *thread,
> @@ -217,9 +208,11 @@ INTERCEPTOR(int, pthread_create, void *thread,
> int detached = 0;
> if (attr)
> REAL(pthread_attr_getdetachstate)(attr, &detached);
> - ThreadStartParam param;
> - atomic_store(¶m.t, 0, memory_order_relaxed);
> - atomic_store(¶m.is_registered, 0, memory_order_relaxed);
> +
> + u32 current_tid = GetCurrentTidOrInvalid();
> + AsanThread *t =
> + AsanThread::Create(start_routine, arg, current_tid, &stack, detached);
> +
> int result;
> {
> // Ignore all allocations made by pthread_create: thread stack/TLS may be
> @@ -229,21 +222,13 @@ INTERCEPTOR(int, pthread_create, void *thread,
> #if CAN_SANITIZE_LEAKS
> __lsan::ScopedInterceptorDisabler disabler;
> #endif
> - result = REAL(pthread_create)(thread, attr, asan_thread_start, ¶m);
> + result = REAL(pthread_create)(thread, attr, asan_thread_start, t);
> }
> - if (result == 0) {
> - u32 current_tid = GetCurrentTidOrInvalid();
> - AsanThread *t =
> - AsanThread::Create(start_routine, arg, current_tid, &stack, detached);
> - atomic_store(¶m.t, reinterpret_cast<uptr>(t), memory_order_release);
> - // Wait until the AsanThread object is initialized and the ThreadRegistry
> - // entry is in "started" state. One reason for this is that after this
> - // interceptor exits, the child thread's stack may be the only thing holding
> - // the |arg| pointer. This may cause LSan to report a leak if leak checking
> - // happens at a point when the interceptor has already exited, but the stack
> - // range for the child thread is not yet known.
> - while (atomic_load(¶m.is_registered, memory_order_acquire) == 0)
> - internal_sched_yield();
> + if (result != 0) {
> + // If the thread didn't start delete the AsanThread to avoid leaking it.
> + // Note AsanThreadContexts never get destroyed so the AsanThreadContext
> + // that was just created for the AsanThread is wasted.
> + t->Destroy();
> }
> return result;
> }
> diff --git a/libsanitizer/asan/asan_interceptors.h b/libsanitizer/asan/asan_interceptors.h
> index 56dc34b7d93..e8c58c2dc6b 100644
> --- a/libsanitizer/asan/asan_interceptors.h
> +++ b/libsanitizer/asan/asan_interceptors.h
> @@ -60,7 +60,7 @@ void InitializePlatformInterceptors();
> # define ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX 0
> #endif
>
> -#if (SANITIZER_LINUX && !SANITIZER_ANDROID) || SANITIZER_SOLARIS
> +#if SANITIZER_GLIBC || SANITIZER_SOLARIS
> # define ASAN_INTERCEPT_SWAPCONTEXT 1
> #else
> # define ASAN_INTERCEPT_SWAPCONTEXT 0
> @@ -72,7 +72,7 @@ void InitializePlatformInterceptors();
> # define ASAN_INTERCEPT_SIGLONGJMP 0
> #endif
>
> -#if SANITIZER_LINUX && !SANITIZER_ANDROID
> +#if SANITIZER_GLIBC
> # define ASAN_INTERCEPT___LONGJMP_CHK 1
> #else
> # define ASAN_INTERCEPT___LONGJMP_CHK 0
> @@ -81,12 +81,7 @@ void InitializePlatformInterceptors();
> #if ASAN_HAS_EXCEPTIONS && !SANITIZER_WINDOWS && !SANITIZER_SOLARIS && \
> !SANITIZER_NETBSD
> # define ASAN_INTERCEPT___CXA_THROW 1
> -# if ! defined(ASAN_HAS_CXA_RETHROW_PRIMARY_EXCEPTION) \
> - || ASAN_HAS_CXA_RETHROW_PRIMARY_EXCEPTION
> -# define ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION 1
> -# else
> -# define ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION 0
> -# endif
> +# define ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION 1
> # if defined(_GLIBCXX_SJLJ_EXCEPTIONS) || (SANITIZER_IOS && defined(__arm__))
> # define ASAN_INTERCEPT__UNWIND_SJLJ_RAISEEXCEPTION 1
> # else
> @@ -111,7 +106,7 @@ void InitializePlatformInterceptors();
> # define ASAN_INTERCEPT_ATEXIT 0
> #endif
>
> -#if SANITIZER_LINUX && !SANITIZER_ANDROID
> +#if SANITIZER_GLIBC
> # define ASAN_INTERCEPT___STRDUP 1
> #else
> # define ASAN_INTERCEPT___STRDUP 0
> @@ -139,10 +134,10 @@ DECLARE_REAL(uptr, strnlen, const char *s, uptr maxlen)
> DECLARE_REAL(char*, strstr, const char *s1, const char *s2)
>
> #if !SANITIZER_MAC
> -#define ASAN_INTERCEPT_FUNC(name) \
> - do { \
> - if (!INTERCEPT_FUNCTION(name)) \
> - VReport(1, "AddressSanitizer: failed to intercept '%s'\n'", #name); \
> +#define ASAN_INTERCEPT_FUNC(name) \
> + do { \
> + if (!INTERCEPT_FUNCTION(name)) \
> + VReport(1, "AddressSanitizer: failed to intercept '%s'\n", #name); \
> } while (0)
> #define ASAN_INTERCEPT_FUNC_VER(name, ver) \
> do { \
> diff --git a/libsanitizer/asan/asan_linux.cpp b/libsanitizer/asan/asan_linux.cpp
> index fb1a442b3d4..4bcbe5d02e3 100644
> --- a/libsanitizer/asan/asan_linux.cpp
> +++ b/libsanitizer/asan/asan_linux.cpp
> @@ -55,6 +55,7 @@ extern Elf_Dyn _DYNAMIC;
> #else
> #include <sys/ucontext.h>
> #include <link.h>
> +extern ElfW(Dyn) _DYNAMIC[];
> #endif
>
> // x86-64 FreeBSD 9.2 and older define 'ucontext_t' incorrectly in
> @@ -84,7 +85,7 @@ bool IsSystemHeapAddress (uptr addr) { return false; }
>
> void *AsanDoesNotSupportStaticLinkage() {
> // This will fail to link with -static.
> - return &_DYNAMIC; // defined in link.h
> + return &_DYNAMIC;
> }
>
> #if ASAN_PREMAP_SHADOW
> diff --git a/libsanitizer/asan/asan_mapping.h b/libsanitizer/asan/asan_mapping.h
> index a7136de60d2..455e2364cd0 100644
> --- a/libsanitizer/asan/asan_mapping.h
> +++ b/libsanitizer/asan/asan_mapping.h
> @@ -72,6 +72,13 @@
> // || `[0x2000000000, 0x23ffffffff]` || LowShadow ||
> // || `[0x0000000000, 0x1fffffffff]` || LowMem ||
> //
> +// Default Linux/RISCV64 Sv39 mapping:
> +// || `[0x1555550000, 0x3fffffffff]` || HighMem ||
> +// || `[0x0fffffa000, 0x1555555fff]` || HighShadow ||
> +// || `[0x0effffa000, 0x0fffff9fff]` || ShadowGap ||
> +// || `[0x0d55550000, 0x0effff9fff]` || LowShadow ||
> +// || `[0x0000000000, 0x0d5554ffff]` || LowMem ||
> +//
> // Default Linux/AArch64 (39-bit VMA) mapping:
> // || `[0x2000000000, 0x7fffffffff]` || highmem ||
> // || `[0x1400000000, 0x1fffffffff]` || highshadow ||
> @@ -79,20 +86,6 @@
> // || `[0x1000000000, 0x11ffffffff]` || lowshadow ||
> // || `[0x0000000000, 0x0fffffffff]` || lowmem ||
> //
> -// RISC-V has only 38 bits for task size
> -// Low mem size is set with kRiscv64_ShadowOffset64 in
> -// compiler-rt/lib/asan/asan_allocator.h and in
> -// llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp with
> -// kRiscv64_ShadowOffset64, High mem top border is set with
> -// GetMaxVirtualAddress() in
> -// compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp
> -// Default Linux/RISCV64 Sv39/Sv48 mapping:
> -// || `[0x000820000000, 0x003fffffffff]` || HighMem ||
> -// || `[0x000124000000, 0x00081fffffff]` || HighShadow ||
> -// || `[0x000024000000, 0x000123ffffff]` || ShadowGap ||
> -// || `[0x000020000000, 0x000023ffffff]` || LowShadow ||
> -// || `[0x000000000000, 0x00001fffffff]` || LowMem ||
> -//
> // Default Linux/AArch64 (42-bit VMA) mapping:
> // || `[0x10000000000, 0x3ffffffffff]` || highmem ||
> // || `[0x0a000000000, 0x0ffffffffff]` || highshadow ||
> @@ -175,10 +168,10 @@ static const u64 kDefaultShadowOffset64 = 1ULL << 44;
> static const u64 kDefaultShort64bitShadowOffset =
> 0x7FFFFFFF & (~0xFFFULL << kDefaultShadowScale); // < 2G.
> static const u64 kAArch64_ShadowOffset64 = 1ULL << 36;
> -static const u64 kRiscv64_ShadowOffset64 = 0x20000000;
> +static const u64 kRiscv64_ShadowOffset64 = 0xd55550000;
> static const u64 kMIPS32_ShadowOffset32 = 0x0aaa0000;
> static const u64 kMIPS64_ShadowOffset64 = 1ULL << 37;
> -static const u64 kPPC64_ShadowOffset64 = 1ULL << 41;
> +static const u64 kPPC64_ShadowOffset64 = 1ULL << 44;
> static const u64 kSystemZ_ShadowOffset64 = 1ULL << 52;
> static const u64 kSPARC64_ShadowOffset64 = 1ULL << 43; // 0x80000000000
> static const u64 kFreeBSD_ShadowOffset32 = 1ULL << 30; // 0x40000000
> diff --git a/libsanitizer/asan/asan_new_delete.cpp b/libsanitizer/asan/asan_new_delete.cpp
> index 5dfcc00fd5d..92a8648452b 100644
> --- a/libsanitizer/asan/asan_new_delete.cpp
> +++ b/libsanitizer/asan/asan_new_delete.cpp
> @@ -45,7 +45,7 @@ COMMENT_EXPORT("??_V@YAXPAX@Z") // operator delete[]
> #endif
> #undef COMMENT_EXPORT
> #else
> -#define CXX_OPERATOR_ATTRIBUTE INTERCEPTOR_ATTRIBUTE
> +#define CXX_OPERATOR_ATTRIBUTE INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
> #endif
>
> using namespace __asan;
> diff --git a/libsanitizer/asan/asan_poisoning.cpp b/libsanitizer/asan/asan_poisoning.cpp
> index 44f872ef619..fa149ecfde6 100644
> --- a/libsanitizer/asan/asan_poisoning.cpp
> +++ b/libsanitizer/asan/asan_poisoning.cpp
> @@ -364,7 +364,7 @@ void __sanitizer_annotate_contiguous_container(const void *beg_p,
> &stack);
> }
> CHECK_LE(end - beg,
> - FIRST_32_SECOND_64(1UL << 30, 1ULL << 34)); // Sanity check.
> + FIRST_32_SECOND_64(1UL << 30, 1ULL << 40)); // Sanity check.
>
> uptr a = RoundDownTo(Min(old_mid, new_mid), granularity);
> uptr c = RoundUpTo(Max(old_mid, new_mid), granularity);
> diff --git a/libsanitizer/asan/asan_posix.cpp b/libsanitizer/asan/asan_posix.cpp
> index d7f19d84654..63ad735f8bb 100644
> --- a/libsanitizer/asan/asan_posix.cpp
> +++ b/libsanitizer/asan/asan_posix.cpp
> @@ -56,7 +56,7 @@ bool PlatformUnpoisonStacks() {
> if (signal_stack.ss_flags != SS_ONSTACK)
> return false;
>
> - // Since we're on the signal altnerate stack, we cannot find the DEFAULT
> + // Since we're on the signal alternate stack, we cannot find the DEFAULT
> // stack bottom using a local variable.
> uptr default_bottom, tls_addr, tls_size, stack_size;
> GetThreadStackAndTls(/*main=*/false, &default_bottom, &stack_size, &tls_addr,
> diff --git a/libsanitizer/asan/asan_rtl.cpp b/libsanitizer/asan/asan_rtl.cpp
> index 7b5a929963c..e715d774228 100644
> --- a/libsanitizer/asan/asan_rtl.cpp
> +++ b/libsanitizer/asan/asan_rtl.cpp
> @@ -62,19 +62,9 @@ static void AsanDie() {
> }
> }
>
> -static void AsanCheckFailed(const char *file, int line, const char *cond,
> - u64 v1, u64 v2) {
> - Report("AddressSanitizer CHECK failed: %s:%d \"%s\" (0x%zx, 0x%zx)\n", file,
> - line, cond, (uptr)v1, (uptr)v2);
> -
> - // Print a stack trace the first time we come here. Otherwise, we probably
> - // failed a CHECK during symbolization.
> - static atomic_uint32_t num_calls;
> - if (atomic_fetch_add(&num_calls, 1, memory_order_relaxed) == 0) {
> - PRINT_CURRENT_STACK_CHECK();
> - }
> -
> - Die();
> +static void CheckUnwind() {
> + GET_STACK_TRACE(kStackTraceMax, common_flags()->fast_unwind_on_check);
> + stack.Print();
> }
>
> // -------------------------- Globals --------------------- {{{1
> @@ -432,7 +422,7 @@ static void AsanInitInternal() {
>
> // Install tool-specific callbacks in sanitizer_common.
> AddDieCallback(AsanDie);
> - SetCheckFailedCallback(AsanCheckFailed);
> + SetCheckUnwindCallback(CheckUnwind);
> SetPrintfAndReportCallback(AppendToErrorMessageBuffer);
>
> __sanitizer_set_report_path(common_flags()->log_path);
> @@ -568,7 +558,7 @@ void UnpoisonStack(uptr bottom, uptr top, const char *type) {
> type, top, bottom, top - bottom, top - bottom);
> return;
> }
> - PoisonShadow(bottom, top - bottom, 0);
> + PoisonShadow(bottom, RoundUpTo(top - bottom, SHADOW_GRANULARITY), 0);
> }
>
> static void UnpoisonDefaultStack() {
> diff --git a/libsanitizer/asan/asan_stack.h b/libsanitizer/asan/asan_stack.h
> index 47ca85a1644..b9575d2f427 100644
> --- a/libsanitizer/asan/asan_stack.h
> +++ b/libsanitizer/asan/asan_stack.h
> @@ -54,9 +54,6 @@ u32 GetMallocContextSize();
> #define GET_STACK_TRACE_FATAL_HERE \
> GET_STACK_TRACE(kStackTraceMax, common_flags()->fast_unwind_on_fatal)
>
> -#define GET_STACK_TRACE_CHECK_HERE \
> - GET_STACK_TRACE(kStackTraceMax, common_flags()->fast_unwind_on_check)
> -
> #define GET_STACK_TRACE_THREAD \
> GET_STACK_TRACE(kStackTraceMax, true)
>
> @@ -71,10 +68,4 @@ u32 GetMallocContextSize();
> stack.Print(); \
> }
>
> -#define PRINT_CURRENT_STACK_CHECK() \
> - { \
> - GET_STACK_TRACE_CHECK_HERE; \
> - stack.Print(); \
> - }
> -
> #endif // ASAN_STACK_H
> diff --git a/libsanitizer/asan/asan_thread.cpp b/libsanitizer/asan/asan_thread.cpp
> index fb09af0ecca..9c3c86f5735 100644
> --- a/libsanitizer/asan/asan_thread.cpp
> +++ b/libsanitizer/asan/asan_thread.cpp
> @@ -100,18 +100,27 @@ void AsanThread::Destroy() {
> int tid = this->tid();
> VReport(1, "T%d exited\n", tid);
>
> - malloc_storage().CommitBack();
> - if (common_flags()->use_sigaltstack) UnsetAlternateSignalStack();
> - asanThreadRegistry().FinishThread(tid);
> - FlushToDeadThreadStats(&stats_);
> - // We also clear the shadow on thread destruction because
> - // some code may still be executing in later TSD destructors
> - // and we don't want it to have any poisoned stack.
> - ClearShadowForThreadStackAndTLS();
> - DeleteFakeStack(tid);
> + bool was_running =
> + (asanThreadRegistry().FinishThread(tid) == ThreadStatusRunning);
> + if (was_running) {
> + if (AsanThread *thread = GetCurrentThread())
> + CHECK_EQ(this, thread);
> + malloc_storage().CommitBack();
> + if (common_flags()->use_sigaltstack)
> + UnsetAlternateSignalStack();
> + FlushToDeadThreadStats(&stats_);
> + // We also clear the shadow on thread destruction because
> + // some code may still be executing in later TSD destructors
> + // and we don't want it to have any poisoned stack.
> + ClearShadowForThreadStackAndTLS();
> + DeleteFakeStack(tid);
> + } else {
> + CHECK_NE(this, GetCurrentThread());
> + }
> uptr size = RoundUpTo(sizeof(AsanThread), GetPageSizeCached());
> UnmapOrDie(this, size);
> - DTLS_Destroy();
> + if (was_running)
> + DTLS_Destroy();
> }
>
> void AsanThread::StartSwitchFiber(FakeStack **fake_stack_save, uptr bottom,
> @@ -219,7 +228,7 @@ FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() {
> }
>
> void AsanThread::Init(const InitOptions *options) {
> - DCHECK_NE(tid(), ThreadRegistry::kUnknownTid);
> + DCHECK_NE(tid(), kInvalidTid);
> next_stack_top_ = next_stack_bottom_ = 0;
> atomic_store(&stack_switching_, false, memory_order_release);
> CHECK_EQ(this->stack_size(), 0U);
> @@ -253,12 +262,9 @@ void AsanThread::Init(const InitOptions *options) {
> // SetThreadStackAndTls.
> #if !SANITIZER_FUCHSIA && !SANITIZER_RTEMS
>
> -thread_return_t AsanThread::ThreadStart(
> - tid_t os_id, atomic_uintptr_t *signal_thread_is_registered) {
> +thread_return_t AsanThread::ThreadStart(tid_t os_id) {
> Init();
> asanThreadRegistry().StartThread(tid(), os_id, ThreadType::Regular, nullptr);
> - if (signal_thread_is_registered)
> - atomic_store(signal_thread_is_registered, 1, memory_order_release);
>
> if (common_flags()->use_sigaltstack) SetAlternateSignalStack();
>
> @@ -285,11 +291,10 @@ thread_return_t AsanThread::ThreadStart(
>
> AsanThread *CreateMainThread() {
> AsanThread *main_thread = AsanThread::Create(
> - /* start_routine */ nullptr, /* arg */ nullptr, /* parent_tid */ 0,
> + /* start_routine */ nullptr, /* arg */ nullptr, /* parent_tid */ kMainTid,
> /* stack */ nullptr, /* detached */ true);
> SetCurrentThread(main_thread);
> - main_thread->ThreadStart(internal_getpid(),
> - /* signal_thread_is_registered */ nullptr);
> + main_thread->ThreadStart(internal_getpid());
> return main_thread;
> }
>
> @@ -300,9 +305,9 @@ void AsanThread::SetThreadStackAndTls(const InitOptions *options) {
> DCHECK_EQ(options, nullptr);
> uptr tls_size = 0;
> uptr stack_size = 0;
> - GetThreadStackAndTls(tid() == 0, &stack_bottom_, &stack_size, &tls_begin_,
> - &tls_size);
> - stack_top_ = stack_bottom_ + stack_size;
> + GetThreadStackAndTls(tid() == kMainTid, &stack_bottom_, &stack_size,
> + &tls_begin_, &tls_size);
> + stack_top_ = RoundDownTo(stack_bottom_ + stack_size, SHADOW_GRANULARITY);
> tls_end_ = tls_begin_ + tls_size;
> dtls_ = DTLS_Get();
>
> @@ -426,7 +431,7 @@ AsanThread *GetCurrentThread() {
> // address. We are not entirely sure that we have correct main thread
> // limits, so only do this magic on Android, and only if the found thread
> // is the main thread.
> - AsanThreadContext *tctx = GetThreadContextByTidLocked(0);
> + AsanThreadContext *tctx = GetThreadContextByTidLocked(kMainTid);
> if (tctx && ThreadStackContainsAddress(tctx, &context)) {
> SetCurrentThread(tctx->thread);
> return tctx->thread;
> @@ -463,7 +468,7 @@ AsanThread *FindThreadByStackAddress(uptr addr) {
> void EnsureMainThreadIDIsCorrect() {
> AsanThreadContext *context =
> reinterpret_cast<AsanThreadContext *>(AsanTSDGet());
> - if (context && (context->tid == 0))
> + if (context && (context->tid == kMainTid))
> context->os_id = GetTid();
> }
>
> diff --git a/libsanitizer/asan/asan_thread.h b/libsanitizer/asan/asan_thread.h
> index ea58de4216a..200069ce0dd 100644
> --- a/libsanitizer/asan/asan_thread.h
> +++ b/libsanitizer/asan/asan_thread.h
> @@ -28,7 +28,6 @@ struct DTLS;
>
> namespace __asan {
>
> -const u32 kInvalidTid = 0xffffff; // Must fit into 24 bits.
> const u32 kMaxNumberOfThreads = (1 << 22); // 4M
>
> class AsanThread;
> @@ -69,8 +68,7 @@ class AsanThread {
> struct InitOptions;
> void Init(const InitOptions *options = nullptr);
>
> - thread_return_t ThreadStart(tid_t os_id,
> - atomic_uintptr_t *signal_thread_is_registered);
> + thread_return_t ThreadStart(tid_t os_id);
>
> uptr stack_top();
> uptr stack_bottom();
> @@ -132,6 +130,8 @@ class AsanThread {
>
> void *extra_spill_area() { return &extra_spill_area_; }
>
> + void *get_arg() { return arg_; }
> +
> private:
> // NOTE: There is no AsanThread constructor. It is allocated
> // via mmap() and *must* be valid in zero-initialized state.
> diff --git a/libsanitizer/asan/asan_win.cpp b/libsanitizer/asan/asan_win.cpp
> index 8044ae16ff9..1577c83cf99 100644
> --- a/libsanitizer/asan/asan_win.cpp
> +++ b/libsanitizer/asan/asan_win.cpp
> @@ -134,7 +134,7 @@ INTERCEPTOR(int, _except_handler4, void *a, void *b, void *c, void *d) {
> static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) {
> AsanThread *t = (AsanThread *)arg;
> SetCurrentThread(t);
> - return t->ThreadStart(GetTid(), /* signal_thread_is_registered */ nullptr);
> + return t->ThreadStart(GetTid());
> }
>
> INTERCEPTOR_WINAPI(HANDLE, CreateThread, LPSECURITY_ATTRIBUTES security,
> diff --git a/libsanitizer/builtins/assembly.h b/libsanitizer/builtins/assembly.h
> index f437cb87f60..9c015059af5 100644
> --- a/libsanitizer/builtins/assembly.h
> +++ b/libsanitizer/builtins/assembly.h
> @@ -14,8 +14,8 @@
> #ifndef COMPILERRT_ASSEMBLY_H
> #define COMPILERRT_ASSEMBLY_H
>
> -#if defined(__POWERPC__) || defined(__powerpc__) || defined(__ppc__)
> -#define SEPARATOR @
> +#if defined(__APPLE__) && defined(__aarch64__)
> +#define SEPARATOR %%
> #else
> #define SEPARATOR ;
> #endif
> @@ -35,14 +35,14 @@
> #define HIDDEN(name) .hidden name
> #define LOCAL_LABEL(name) .L_##name
> #define FILE_LEVEL_DIRECTIVE
> -#if defined(__arm__)
> +#if defined(__arm__) || defined(__aarch64__)
> #define SYMBOL_IS_FUNC(name) .type name,%function
> #else
> #define SYMBOL_IS_FUNC(name) .type name,@function
> #endif
> #define CONST_SECTION .section .rodata
>
> -#if defined(__GNU__) || defined(__FreeBSD__) || defined(__Fuchsia__) || \
> +#if defined(__GNU__) || defined(__FreeBSD__) || defined(__Fuchsia__) || \
> defined(__linux__)
> #define NO_EXEC_STACK_DIRECTIVE .section .note.GNU-stack,"",%progbits
> #else
> @@ -65,6 +65,68 @@
>
> #endif
>
> +#if defined(__arm__) || defined(__aarch64__)
> +#define FUNC_ALIGN \
> + .text SEPARATOR \
> + .balign 16 SEPARATOR
> +#else
> +#define FUNC_ALIGN
> +#endif
> +
> +// BTI and PAC gnu property note
> +#define NT_GNU_PROPERTY_TYPE_0 5
> +#define GNU_PROPERTY_AARCH64_FEATURE_1_AND 0xc0000000
> +#define GNU_PROPERTY_AARCH64_FEATURE_1_BTI 1
> +#define GNU_PROPERTY_AARCH64_FEATURE_1_PAC 2
> +
> +#if defined(__ARM_FEATURE_BTI_DEFAULT)
> +#define BTI_FLAG GNU_PROPERTY_AARCH64_FEATURE_1_BTI
> +#else
> +#define BTI_FLAG 0
> +#endif
> +
> +#if __ARM_FEATURE_PAC_DEFAULT & 3
> +#define PAC_FLAG GNU_PROPERTY_AARCH64_FEATURE_1_PAC
> +#else
> +#define PAC_FLAG 0
> +#endif
> +
> +#define GNU_PROPERTY(type, value) \
> + .pushsection .note.gnu.property, "a" SEPARATOR \
> + .p2align 3 SEPARATOR \
> + .word 4 SEPARATOR \
> + .word 16 SEPARATOR \
> + .word NT_GNU_PROPERTY_TYPE_0 SEPARATOR \
> + .asciz "GNU" SEPARATOR \
> + .word type SEPARATOR \
> + .word 4 SEPARATOR \
> + .word value SEPARATOR \
> + .word 0 SEPARATOR \
> + .popsection
> +
> +#if BTI_FLAG != 0
> +#define BTI_C hint #34
> +#define BTI_J hint #36
> +#else
> +#define BTI_C
> +#define BTI_J
> +#endif
> +
> +#if (BTI_FLAG | PAC_FLAG) != 0
> +#define GNU_PROPERTY_BTI_PAC \
> + GNU_PROPERTY(GNU_PROPERTY_AARCH64_FEATURE_1_AND, BTI_FLAG | PAC_FLAG)
> +#else
> +#define GNU_PROPERTY_BTI_PAC
> +#endif
> +
> +#if defined(__clang__) || defined(__GCC_HAVE_DWARF2_CFI_ASM)
> +#define CFI_START .cfi_startproc
> +#define CFI_END .cfi_endproc
> +#else
> +#define CFI_START
> +#define CFI_END
> +#endif
> +
> #if defined(__arm__)
>
> // Determine actual [ARM][THUMB[1][2]] ISA using compiler predefined macros:
> @@ -131,15 +193,24 @@
> #define DEFINE_CODE_STATE
> #endif
>
> -#define GLUE2(a, b) a##b
> -#define GLUE(a, b) GLUE2(a, b)
> +#define GLUE2_(a, b) a##b
> +#define GLUE(a, b) GLUE2_(a, b)
> +#define GLUE2(a, b) GLUE2_(a, b)
> +#define GLUE3_(a, b, c) a##b##c
> +#define GLUE3(a, b, c) GLUE3_(a, b, c)
> +#define GLUE4_(a, b, c, d) a##b##c##d
> +#define GLUE4(a, b, c, d) GLUE4_(a, b, c, d)
> +
> #define SYMBOL_NAME(name) GLUE(__USER_LABEL_PREFIX__, name)
>
> #ifdef VISIBILITY_HIDDEN
> #define DECLARE_SYMBOL_VISIBILITY(name) \
> HIDDEN(SYMBOL_NAME(name)) SEPARATOR
> +#define DECLARE_SYMBOL_VISIBILITY_UNMANGLED(name) \
> + HIDDEN(name) SEPARATOR
> #else
> #define DECLARE_SYMBOL_VISIBILITY(name)
> +#define DECLARE_SYMBOL_VISIBILITY_UNMANGLED(name)
> #endif
>
> #define DEFINE_COMPILERRT_FUNCTION(name) \
> @@ -177,6 +248,16 @@
> DECLARE_FUNC_ENCODING \
> name:
>
> +#define DEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(name) \
> + DEFINE_CODE_STATE \
> + FUNC_ALIGN \
> + .globl name SEPARATOR \
> + SYMBOL_IS_FUNC(name) SEPARATOR \
> + DECLARE_SYMBOL_VISIBILITY_UNMANGLED(name) SEPARATOR \
> + CFI_START SEPARATOR \
> + DECLARE_FUNC_ENCODING \
> + name: SEPARATOR BTI_C
> +
> #define DEFINE_COMPILERRT_FUNCTION_ALIAS(name, target) \
> .globl SYMBOL_NAME(name) SEPARATOR \
> SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \
> @@ -193,8 +274,13 @@
> #ifdef __ELF__
> #define END_COMPILERRT_FUNCTION(name) \
> .size SYMBOL_NAME(name), . - SYMBOL_NAME(name)
> +#define END_COMPILERRT_OUTLINE_FUNCTION(name) \
> + CFI_END SEPARATOR \
> + .size SYMBOL_NAME(name), . - SYMBOL_NAME(name)
> #else
> #define END_COMPILERRT_FUNCTION(name)
> +#define END_COMPILERRT_OUTLINE_FUNCTION(name) \
> + CFI_END
> #endif
>
> #endif // COMPILERRT_ASSEMBLY_H
> diff --git a/libsanitizer/hwasan/hwasan.cpp b/libsanitizer/hwasan/hwasan.cpp
> index c5322110cb6..8d6c25261b8 100644
> --- a/libsanitizer/hwasan/hwasan.cpp
> +++ b/libsanitizer/hwasan/hwasan.cpp
> @@ -128,16 +128,11 @@ static void InitializeFlags() {
> if (common_flags()->help) parser.PrintFlagDescriptions();
> }
>
> -static void HWAsanCheckFailed(const char *file, int line, const char *cond,
> - u64 v1, u64 v2) {
> - Report("HWAddressSanitizer CHECK failed: %s:%d \"%s\" (0x%zx, 0x%zx)\n", file,
> - line, cond, (uptr)v1, (uptr)v2);
> - PRINT_CURRENT_STACK_CHECK();
> - Die();
> +static void CheckUnwind() {
> + GET_FATAL_STACK_TRACE_PC_BP(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME());
> + stack.Print();
> }
>
> -static constexpr uptr kMemoryUsageBufferSize = 4096;
> -
> static void HwasanFormatMemoryUsage(InternalScopedString &s) {
> HwasanThreadList &thread_list = hwasanThreadList();
> auto thread_stats = thread_list.GetThreadStats();
> @@ -155,6 +150,8 @@ static void HwasanFormatMemoryUsage(InternalScopedString &s) {
> }
>
> #if SANITIZER_ANDROID
> +static constexpr uptr kMemoryUsageBufferSize = 4096;
> +
> static char *memory_usage_buffer = nullptr;
>
> static void InitMemoryUsage() {
> @@ -171,7 +168,7 @@ void UpdateMemoryUsage() {
> return;
> if (!memory_usage_buffer)
> InitMemoryUsage();
> - InternalScopedString s(kMemoryUsageBufferSize);
> + InternalScopedString s;
> HwasanFormatMemoryUsage(s);
> internal_strncpy(memory_usage_buffer, s.data(), kMemoryUsageBufferSize - 1);
> memory_usage_buffer[kMemoryUsageBufferSize - 1] = '\0';
> @@ -271,7 +268,7 @@ void __hwasan_init() {
> InitializeFlags();
>
> // Install tool-specific callbacks in sanitizer_common.
> - SetCheckFailedCallback(HWAsanCheckFailed);
> + SetCheckUnwindCallback(CheckUnwind);
>
> __sanitizer_set_report_path(common_flags()->log_path);
>
> @@ -493,7 +490,7 @@ extern "C" void *__hwasan_extra_spill_area() {
> }
>
> void __hwasan_print_memory_usage() {
> - InternalScopedString s(kMemoryUsageBufferSize);
> + InternalScopedString s;
> HwasanFormatMemoryUsage(s);
> Printf("%s\n", s.data());
> }
> diff --git a/libsanitizer/hwasan/hwasan.h b/libsanitizer/hwasan/hwasan.h
> index d4521efd089..8515df559f3 100644
> --- a/libsanitizer/hwasan/hwasan.h
> +++ b/libsanitizer/hwasan/hwasan.h
> @@ -14,11 +14,12 @@
> #ifndef HWASAN_H
> #define HWASAN_H
>
> +#include "hwasan_flags.h"
> +#include "hwasan_interface_internal.h"
> +#include "sanitizer_common/sanitizer_common.h"
> #include "sanitizer_common/sanitizer_flags.h"
> #include "sanitizer_common/sanitizer_internal_defs.h"
> #include "sanitizer_common/sanitizer_stacktrace.h"
> -#include "hwasan_interface_internal.h"
> -#include "hwasan_flags.h"
> #include "ubsan/ubsan_platform.h"
>
> #ifndef HWASAN_CONTAINS_UBSAN
> @@ -35,10 +36,31 @@
>
> typedef u8 tag_t;
>
> +#if defined(__x86_64__)
> +// Tags are done in middle bits using userspace aliasing.
> +constexpr unsigned kAddressTagShift = 39;
> +constexpr unsigned kTagBits = 3;
> +
> +// The alias region is placed next to the shadow so the upper bits of all
> +// taggable addresses matches the upper bits of the shadow base. This shift
> +// value determines which upper bits must match. It has a floor of 44 since the
> +// shadow is always 8TB.
> +// TODO(morehouse): In alias mode we can shrink the shadow and use a
> +// simpler/faster shadow calculation.
> +constexpr unsigned kTaggableRegionCheckShift =
> + __sanitizer::Max(kAddressTagShift + kTagBits + 1U, 44U);
> +#else
> // TBI (Top Byte Ignore) feature of AArch64: bits [63:56] are ignored in address
> // translation and can be used to store a tag.
> -const unsigned kAddressTagShift = 56;
> -const uptr kAddressTagMask = 0xFFUL << kAddressTagShift;
> +constexpr unsigned kAddressTagShift = 56;
> +constexpr unsigned kTagBits = 8;
> +#endif // defined(__x86_64__)
> +
> +// Mask for extracting tag bits from the lower 8 bits.
> +constexpr uptr kTagMask = (1UL << kTagBits) - 1;
> +
> +// Mask for extracting tag bits from full pointers.
> +constexpr uptr kAddressTagMask = kTagMask << kAddressTagShift;
>
> // Minimal alignment of the shadow base address. Determines the space available
> // for threads and stack histories. This is an ABI constant.
> @@ -50,7 +72,7 @@ const unsigned kRecordFPLShift = 4;
> const unsigned kRecordFPModulus = 1 << (64 - kRecordFPShift + kRecordFPLShift);
>
> static inline tag_t GetTagFromPointer(uptr p) {
> - return p >> kAddressTagShift;
> + return (p >> kAddressTagShift) & kTagMask;
> }
>
> static inline uptr UntagAddr(uptr tagged_addr) {
> @@ -105,15 +127,6 @@ void InstallAtExitHandler();
> if (hwasan_inited) \
> stack.Unwind(pc, bp, nullptr, common_flags()->fast_unwind_on_fatal)
>
> -#define GET_FATAL_STACK_TRACE_HERE \
> - GET_FATAL_STACK_TRACE_PC_BP(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME())
> -
> -#define PRINT_CURRENT_STACK_CHECK() \
> - { \
> - GET_FATAL_STACK_TRACE_HERE; \
> - stack.Print(); \
> - }
> -
> void HwasanTSDInit();
> void HwasanTSDThreadInit();
>
> diff --git a/libsanitizer/hwasan/hwasan_allocator.cpp b/libsanitizer/hwasan/hwasan_allocator.cpp
> index 0b6b7347892..a6fc794082a 100644
> --- a/libsanitizer/hwasan/hwasan_allocator.cpp
> +++ b/libsanitizer/hwasan/hwasan_allocator.cpp
> @@ -29,8 +29,8 @@ static AllocatorCache fallback_allocator_cache;
> static SpinMutex fallback_mutex;
> static atomic_uint8_t hwasan_allocator_tagging_enabled;
>
> -static const tag_t kFallbackAllocTag = 0xBB;
> -static const tag_t kFallbackFreeTag = 0xBC;
> +static constexpr tag_t kFallbackAllocTag = 0xBB & kTagMask;
> +static constexpr tag_t kFallbackFreeTag = 0xBC;
>
> enum RightAlignMode {
> kRightAlignNever,
> @@ -84,7 +84,8 @@ void HwasanAllocatorInit() {
> atomic_store_relaxed(&hwasan_allocator_tagging_enabled,
> !flags()->disable_allocator_tagging);
> SetAllocatorMayReturnNull(common_flags()->allocator_may_return_null);
> - allocator.Init(common_flags()->allocator_release_to_os_interval_ms);
> + allocator.Init(common_flags()->allocator_release_to_os_interval_ms,
> + kAliasRegionStart);
> for (uptr i = 0; i < sizeof(tail_magic); i++)
> tail_magic[i] = GetCurrentThread()->GenerateRandomTag();
> }
> @@ -148,7 +149,8 @@ static void *HwasanAllocate(StackTrace *stack, uptr orig_size, uptr alignment,
> // Tagging can only be skipped when both tag_in_malloc and tag_in_free are
> // false. When tag_in_malloc = false and tag_in_free = true malloc needs to
> // retag to 0.
> - if ((flags()->tag_in_malloc || flags()->tag_in_free) &&
> + if (InTaggableRegion(reinterpret_cast<uptr>(user_ptr)) &&
> + (flags()->tag_in_malloc || flags()->tag_in_free) &&
> atomic_load_relaxed(&hwasan_allocator_tagging_enabled)) {
> if (flags()->tag_in_malloc && malloc_bisect(stack, orig_size)) {
> tag_t tag = t ? t->GenerateRandomTag() : kFallbackAllocTag;
> @@ -175,6 +177,8 @@ static void *HwasanAllocate(StackTrace *stack, uptr orig_size, uptr alignment,
> static bool PointerAndMemoryTagsMatch(void *tagged_ptr) {
> CHECK(tagged_ptr);
> uptr tagged_uptr = reinterpret_cast<uptr>(tagged_ptr);
> + if (!InTaggableRegion(tagged_uptr))
> + return true;
> tag_t mem_tag = *reinterpret_cast<tag_t *>(
> MemToShadow(reinterpret_cast<uptr>(UntagPtr(tagged_ptr))));
> return PossiblyShortTagMatches(mem_tag, tagged_uptr, 1);
> @@ -187,7 +191,9 @@ static void HwasanDeallocate(StackTrace *stack, void *tagged_ptr) {
> if (!PointerAndMemoryTagsMatch(tagged_ptr))
> ReportInvalidFree(stack, reinterpret_cast<uptr>(tagged_ptr));
>
> - void *untagged_ptr = UntagPtr(tagged_ptr);
> + void *untagged_ptr = InTaggableRegion(reinterpret_cast<uptr>(tagged_ptr))
> + ? UntagPtr(tagged_ptr)
> + : tagged_ptr;
> void *aligned_ptr = reinterpret_cast<void *>(
> RoundDownTo(reinterpret_cast<uptr>(untagged_ptr), kShadowAlignment));
> Metadata *meta =
> @@ -219,10 +225,14 @@ static void HwasanDeallocate(StackTrace *stack, void *tagged_ptr) {
> Min(TaggedSize(orig_size), (uptr)flags()->max_free_fill_size);
> internal_memset(aligned_ptr, flags()->free_fill_byte, fill_size);
> }
> - if (flags()->tag_in_free && malloc_bisect(stack, 0) &&
> - atomic_load_relaxed(&hwasan_allocator_tagging_enabled))
> + if (InTaggableRegion(reinterpret_cast<uptr>(tagged_ptr)) &&
> + flags()->tag_in_free && malloc_bisect(stack, 0) &&
> + atomic_load_relaxed(&hwasan_allocator_tagging_enabled)) {
> + // Always store full 8-bit tags on free to maximize UAF detection.
> + tag_t tag = t ? t->GenerateRandomTag(/*num_bits=*/8) : kFallbackFreeTag;
> TagMemoryAligned(reinterpret_cast<uptr>(aligned_ptr), TaggedSize(orig_size),
> - t ? t->GenerateRandomTag() : kFallbackFreeTag);
> + tag);
> + }
> if (t) {
> allocator.Deallocate(t->allocator_cache(), aligned_ptr);
> if (auto *ha = t->heap_allocations())
> @@ -365,7 +375,7 @@ int hwasan_posix_memalign(void **memptr, uptr alignment, uptr size,
> // OOM error is already taken care of by HwasanAllocate.
> return errno_ENOMEM;
> CHECK(IsAligned((uptr)ptr, alignment));
> - *(void **)UntagPtr(memptr) = ptr;
> + *memptr = ptr;
> return 0;
> }
>
> diff --git a/libsanitizer/hwasan/hwasan_allocator.h b/libsanitizer/hwasan/hwasan_allocator.h
> index 43670a6a3fb..03bbcff3f0f 100644
> --- a/libsanitizer/hwasan/hwasan_allocator.h
> +++ b/libsanitizer/hwasan/hwasan_allocator.h
> @@ -13,13 +13,15 @@
> #ifndef HWASAN_ALLOCATOR_H
> #define HWASAN_ALLOCATOR_H
>
> +#include "hwasan.h"
> +#include "hwasan_interface_internal.h"
> +#include "hwasan_poisoning.h"
> #include "sanitizer_common/sanitizer_allocator.h"
> #include "sanitizer_common/sanitizer_allocator_checks.h"
> #include "sanitizer_common/sanitizer_allocator_interface.h"
> #include "sanitizer_common/sanitizer_allocator_report.h"
> #include "sanitizer_common/sanitizer_common.h"
> #include "sanitizer_common/sanitizer_ring_buffer.h"
> -#include "hwasan_poisoning.h"
>
> #if !defined(__aarch64__) && !defined(__x86_64__)
> #error Unsupported platform
> @@ -55,7 +57,12 @@ static const uptr kMaxAllowedMallocSize = 1UL << 40; // 1T
>
> struct AP64 {
> static const uptr kSpaceBeg = ~0ULL;
> +
> +#if defined(__x86_64__)
> + static const uptr kSpaceSize = 1ULL << kAddressTagShift;
> +#else
> static const uptr kSpaceSize = 0x2000000000ULL;
> +#endif
> static const uptr kMetadataSize = sizeof(Metadata);
> typedef __sanitizer::VeryDenseSizeClassMap SizeClassMap;
> using AddressSpaceView = LocalAddressSpaceView;
> @@ -102,6 +109,16 @@ typedef RingBuffer<HeapAllocationRecord> HeapAllocationsRingBuffer;
>
> void GetAllocatorStats(AllocatorStatCounters s);
>
> +inline bool InTaggableRegion(uptr addr) {
> +#if defined(__x86_64__)
> + // Aliases are mapped next to shadow so that the upper bits match the shadow
> + // base.
> + return (addr >> kTaggableRegionCheckShift) ==
> + (__hwasan_shadow_memory_dynamic_address >> kTaggableRegionCheckShift);
> +#endif
> + return true;
> +}
> +
> } // namespace __hwasan
>
> #endif // HWASAN_ALLOCATOR_H
> diff --git a/libsanitizer/hwasan/hwasan_checks.h b/libsanitizer/hwasan/hwasan_checks.h
> index a8de0fef20f..ab543ea88be 100644
> --- a/libsanitizer/hwasan/hwasan_checks.h
> +++ b/libsanitizer/hwasan/hwasan_checks.h
> @@ -13,6 +13,7 @@
> #ifndef HWASAN_CHECKS_H
> #define HWASAN_CHECKS_H
>
> +#include "hwasan_allocator.h"
> #include "hwasan_mapping.h"
> #include "sanitizer_common/sanitizer_common.h"
>
> @@ -81,6 +82,8 @@ enum class AccessType { Load, Store };
>
> template <ErrorAction EA, AccessType AT, unsigned LogSize>
> __attribute__((always_inline, nodebug)) static void CheckAddress(uptr p) {
> + if (!InTaggableRegion(p))
> + return;
> uptr ptr_raw = p & ~kAddressTagMask;
> tag_t mem_tag = *(tag_t *)MemToShadow(ptr_raw);
> if (UNLIKELY(!PossiblyShortTagMatches(mem_tag, p, 1 << LogSize))) {
> @@ -94,7 +97,7 @@ __attribute__((always_inline, nodebug)) static void CheckAddress(uptr p) {
> template <ErrorAction EA, AccessType AT>
> __attribute__((always_inline, nodebug)) static void CheckAddressSized(uptr p,
> uptr sz) {
> - if (sz == 0)
> + if (sz == 0 || !InTaggableRegion(p))
> return;
> tag_t ptr_tag = GetTagFromPointer(p);
> uptr ptr_raw = p & ~kAddressTagMask;
> diff --git a/libsanitizer/hwasan/hwasan_dynamic_shadow.cpp b/libsanitizer/hwasan/hwasan_dynamic_shadow.cpp
> index 12730b29bae..f53276e330d 100644
> --- a/libsanitizer/hwasan/hwasan_dynamic_shadow.cpp
> +++ b/libsanitizer/hwasan/hwasan_dynamic_shadow.cpp
> @@ -12,15 +12,17 @@
> ///
> //===----------------------------------------------------------------------===//
>
> -#include "hwasan.h"
> #include "hwasan_dynamic_shadow.h"
> -#include "hwasan_mapping.h"
> -#include "sanitizer_common/sanitizer_common.h"
> -#include "sanitizer_common/sanitizer_posix.h"
>
> #include <elf.h>
> #include <link.h>
>
> +#include "hwasan.h"
> +#include "hwasan_mapping.h"
> +#include "hwasan_thread_list.h"
> +#include "sanitizer_common/sanitizer_common.h"
> +#include "sanitizer_common/sanitizer_posix.h"
> +
> // The code in this file needs to run in an unrelocated binary. It should not
> // access any external symbol, including its own non-hidden globals.
>
> @@ -117,6 +119,12 @@ namespace __hwasan {
> void InitShadowGOT() {}
>
> uptr FindDynamicShadowStart(uptr shadow_size_bytes) {
> +#if defined(__x86_64__)
> + constexpr uptr kAliasSize = 1ULL << kAddressTagShift;
> + constexpr uptr kNumAliases = 1ULL << kTagBits;
> + return MapDynamicShadowAndAliases(shadow_size_bytes, kAliasSize, kNumAliases,
> + RingBufferSize());
> +#endif
> return MapDynamicShadow(shadow_size_bytes, kShadowScale, kShadowBaseAlignment,
> kHighMemEnd);
> }
> diff --git a/libsanitizer/hwasan/hwasan_flags.h b/libsanitizer/hwasan/hwasan_flags.h
> index 0a6998f675d..b17750158d0 100644
> --- a/libsanitizer/hwasan/hwasan_flags.h
> +++ b/libsanitizer/hwasan/hwasan_flags.h
> @@ -12,6 +12,8 @@
> #ifndef HWASAN_FLAGS_H
> #define HWASAN_FLAGS_H
>
> +#include "sanitizer_common/sanitizer_internal_defs.h"
> +
> namespace __hwasan {
>
> struct Flags {
> diff --git a/libsanitizer/hwasan/hwasan_flags.inc b/libsanitizer/hwasan/hwasan_flags.inc
> index 8e431d9c4ff..18ea47f981b 100644
> --- a/libsanitizer/hwasan/hwasan_flags.inc
> +++ b/libsanitizer/hwasan/hwasan_flags.inc
> @@ -72,3 +72,12 @@ HWASAN_FLAG(uptr, malloc_bisect_right, 0,
> HWASAN_FLAG(bool, malloc_bisect_dump, false,
> "Print all allocations within [malloc_bisect_left, "
> "malloc_bisect_right] range ")
> +
> +
> +// Exit if we fail to enable the AArch64 kernel ABI relaxation which allows
> +// tagged pointers in syscalls. This is the default, but being able to disable
> +// that behaviour is useful for running the testsuite on more platforms (the
> +// testsuite can run since we manually ensure any pointer arguments to syscalls
> +// are untagged before the call.
> +HWASAN_FLAG(bool, fail_without_syscall_abi, true,
> + "Exit if fail to request relaxed syscall ABI.")
> diff --git a/libsanitizer/hwasan/hwasan_interceptors.cpp b/libsanitizer/hwasan/hwasan_interceptors.cpp
> index 44e569ee6d7..ad67e2787d3 100644
> --- a/libsanitizer/hwasan/hwasan_interceptors.cpp
> +++ b/libsanitizer/hwasan/hwasan_interceptors.cpp
> @@ -221,8 +221,7 @@ INTERCEPTOR(int, pthread_create, void *th, void *attr, void *(*callback)(void*),
> ThreadStartArg *A = reinterpret_cast<ThreadStartArg *> (MmapOrDie(
> GetPageSizeCached(), "pthread_create"));
> *A = {callback, param};
> - int res = REAL(pthread_create)(UntagPtr(th), UntagPtr(attr),
> - &HwasanThreadStartFunc, A);
> + int res = REAL(pthread_create)(th, attr, &HwasanThreadStartFunc, A);
> return res;
> }
>
> diff --git a/libsanitizer/hwasan/hwasan_interceptors_vfork.S b/libsanitizer/hwasan/hwasan_interceptors_vfork.S
> index 23d565936d8..fd20825e3da 100644
> --- a/libsanitizer/hwasan/hwasan_interceptors_vfork.S
> +++ b/libsanitizer/hwasan/hwasan_interceptors_vfork.S
> @@ -1,4 +1,5 @@
> #include "sanitizer_common/sanitizer_asm.h"
> +#include "builtins/assembly.h"
>
> #if defined(__linux__) && HWASAN_WITH_INTERCEPTORS
> #define COMMON_INTERCEPTOR_SPILL_AREA __hwasan_extra_spill_area
> @@ -9,3 +10,5 @@
> #endif
>
> NO_EXEC_STACK_DIRECTIVE
> +
> +GNU_PROPERTY_BTI_PAC
> diff --git a/libsanitizer/hwasan/hwasan_interface_internal.h b/libsanitizer/hwasan/hwasan_interface_internal.h
> index aedda317497..25c0f94fe51 100644
> --- a/libsanitizer/hwasan/hwasan_interface_internal.h
> +++ b/libsanitizer/hwasan/hwasan_interface_internal.h
> @@ -222,6 +222,9 @@ SANITIZER_INTERFACE_ATTRIBUTE
> void *__hwasan_memset(void *s, int c, uptr n);
> SANITIZER_INTERFACE_ATTRIBUTE
> void *__hwasan_memmove(void *dest, const void *src, uptr n);
> +
> +SANITIZER_INTERFACE_ATTRIBUTE
> +void __hwasan_set_error_report_callback(void (*callback)(const char *));
> } // extern "C"
>
> #endif // HWASAN_INTERFACE_INTERNAL_H
> diff --git a/libsanitizer/hwasan/hwasan_linux.cpp b/libsanitizer/hwasan/hwasan_linux.cpp
> index e99926d355c..8ce0ff7da95 100644
> --- a/libsanitizer/hwasan/hwasan_linux.cpp
> +++ b/libsanitizer/hwasan/hwasan_linux.cpp
> @@ -76,6 +76,8 @@ uptr kHighShadowEnd;
> uptr kHighMemStart;
> uptr kHighMemEnd;
>
> +uptr kAliasRegionStart; // Always 0 on non-x86.
> +
> static void PrintRange(uptr start, uptr end, const char *name) {
> Printf("|| [%p, %p] || %.*s ||\n", (void *)start, (void *)end, 10, name);
> }
> @@ -119,9 +121,11 @@ void InitPrctl() {
> #define PR_GET_TAGGED_ADDR_CTRL 56
> #define PR_TAGGED_ADDR_ENABLE (1UL << 0)
> // Check we're running on a kernel that can use the tagged address ABI.
> - if (internal_prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0) == (uptr)-1 &&
> - errno == EINVAL) {
> -#if SANITIZER_ANDROID
> + int local_errno = 0;
> + if (internal_iserror(internal_prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0),
> + &local_errno) &&
> + local_errno == EINVAL) {
> +#if SANITIZER_ANDROID || defined(__x86_64__)
> // Some older Android kernels have the tagged pointer ABI on
> // unconditionally, and hence don't have the tagged-addr prctl while still
> // allow the ABI.
> @@ -129,17 +133,20 @@ void InitPrctl() {
> // case.
> return;
> #else
> - Printf(
> - "FATAL: "
> - "HWAddressSanitizer requires a kernel with tagged address ABI.\n");
> - Die();
> + if (flags()->fail_without_syscall_abi) {
> + Printf(
> + "FATAL: "
> + "HWAddressSanitizer requires a kernel with tagged address ABI.\n");
> + Die();
> + }
> #endif
> }
>
> // Turn on the tagged address ABI.
> - if (internal_prctl(PR_SET_TAGGED_ADDR_CTRL, PR_TAGGED_ADDR_ENABLE, 0, 0, 0) ==
> - (uptr)-1 ||
> - !internal_prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0)) {
> + if ((internal_iserror(internal_prctl(PR_SET_TAGGED_ADDR_CTRL,
> + PR_TAGGED_ADDR_ENABLE, 0, 0, 0)) ||
> + !internal_prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0)) &&
> + flags()->fail_without_syscall_abi) {
> Printf(
> "FATAL: HWAddressSanitizer failed to enable tagged address syscall "
> "ABI.\nSuggest check `sysctl abi.tagged_addr_disabled` "
> @@ -174,6 +181,18 @@ bool InitShadow() {
> // High memory starts where allocated shadow allows.
> kHighMemStart = ShadowToMem(kHighShadowStart);
>
> +#if defined(__x86_64__)
> + constexpr uptr kAliasRegionOffset = 1ULL << (kTaggableRegionCheckShift - 1);
> + kAliasRegionStart =
> + __hwasan_shadow_memory_dynamic_address + kAliasRegionOffset;
> +
> + CHECK_EQ(kAliasRegionStart >> kTaggableRegionCheckShift,
> + __hwasan_shadow_memory_dynamic_address >> kTaggableRegionCheckShift);
> + CHECK_EQ(
> + (kAliasRegionStart + kAliasRegionOffset - 1) >> kTaggableRegionCheckShift,
> + __hwasan_shadow_memory_dynamic_address >> kTaggableRegionCheckShift);
> +#endif
> +
> // Check the sanity of the defined memory ranges (there might be gaps).
> CHECK_EQ(kHighMemStart % GetMmapGranularity(), 0);
> CHECK_GT(kHighMemStart, kHighShadowEnd);
> @@ -217,7 +236,9 @@ void InitThreads() {
> }
>
> bool MemIsApp(uptr p) {
> +#if !defined(__x86_64__) // Memory outside the alias range has non-zero tags.
> CHECK(GetTagFromPointer(p) == 0);
> +#endif
> return p >= kHighMemStart || (p >= kLowMemStart && p <= kLowMemEnd);
> }
>
> diff --git a/libsanitizer/hwasan/hwasan_mapping.h b/libsanitizer/hwasan/hwasan_mapping.h
> index c149687bdfa..8243d1ec7ed 100644
> --- a/libsanitizer/hwasan/hwasan_mapping.h
> +++ b/libsanitizer/hwasan/hwasan_mapping.h
> @@ -48,6 +48,8 @@ extern uptr kHighShadowEnd;
> extern uptr kHighMemStart;
> extern uptr kHighMemEnd;
>
> +extern uptr kAliasRegionStart;
> +
> inline uptr MemToShadow(uptr untagged_addr) {
> return (untagged_addr >> kShadowScale) +
> __hwasan_shadow_memory_dynamic_address;
> diff --git a/libsanitizer/hwasan/hwasan_memintrinsics.cpp b/libsanitizer/hwasan/hwasan_memintrinsics.cpp
> index e82d77a1bc1..fab017aae60 100644
> --- a/libsanitizer/hwasan/hwasan_memintrinsics.cpp
> +++ b/libsanitizer/hwasan/hwasan_memintrinsics.cpp
> @@ -24,7 +24,7 @@ using namespace __hwasan;
> void *__hwasan_memset(void *block, int c, uptr size) {
> CheckAddressSized<ErrorAction::Recover, AccessType::Store>(
> reinterpret_cast<uptr>(block), size);
> - return memset(UntagPtr(block), c, size);
> + return memset(block, c, size);
> }
>
> void *__hwasan_memcpy(void *to, const void *from, uptr size) {
> @@ -32,7 +32,7 @@ void *__hwasan_memcpy(void *to, const void *from, uptr size) {
> reinterpret_cast<uptr>(to), size);
> CheckAddressSized<ErrorAction::Recover, AccessType::Load>(
> reinterpret_cast<uptr>(from), size);
> - return memcpy(UntagPtr(to), UntagPtr(from), size);
> + return memcpy(to, from, size);
> }
>
> void *__hwasan_memmove(void *to, const void *from, uptr size) {
> diff --git a/libsanitizer/hwasan/hwasan_new_delete.cpp b/libsanitizer/hwasan/hwasan_new_delete.cpp
> index 8d01d3944f2..69cddda736e 100644
> --- a/libsanitizer/hwasan/hwasan_new_delete.cpp
> +++ b/libsanitizer/hwasan/hwasan_new_delete.cpp
> @@ -27,6 +27,12 @@
> void *res = hwasan_malloc(size, &stack);\
> if (!nothrow && UNLIKELY(!res)) ReportOutOfMemory(size, &stack);\
> return res
> +#define OPERATOR_NEW_ALIGN_BODY(nothrow) \
> + GET_MALLOC_STACK_TRACE; \
> + void *res = hwasan_aligned_alloc(static_cast<uptr>(align), size, &stack); \
> + if (!nothrow && UNLIKELY(!res)) \
> + ReportOutOfMemory(size, &stack); \
> + return res
>
> #define OPERATOR_DELETE_BODY \
> GET_MALLOC_STACK_TRACE; \
> @@ -50,6 +56,7 @@ using namespace __hwasan;
> // Fake std::nothrow_t to avoid including <new>.
> namespace std {
> struct nothrow_t {};
> + enum class align_val_t : size_t {};
> } // namespace std
>
>
> @@ -66,6 +73,22 @@ INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
> void *operator new[](size_t size, std::nothrow_t const&) {
> OPERATOR_NEW_BODY(true /*nothrow*/);
> }
> +INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void *operator new(
> + size_t size, std::align_val_t align) {
> + OPERATOR_NEW_ALIGN_BODY(false /*nothrow*/);
> +}
> +INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void *operator new[](
> + size_t size, std::align_val_t align) {
> + OPERATOR_NEW_ALIGN_BODY(false /*nothrow*/);
> +}
> +INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void *operator new(
> + size_t size, std::align_val_t align, std::nothrow_t const &) {
> + OPERATOR_NEW_ALIGN_BODY(true /*nothrow*/);
> +}
> +INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void *operator new[](
> + size_t size, std::align_val_t align, std::nothrow_t const &) {
> + OPERATOR_NEW_ALIGN_BODY(true /*nothrow*/);
> +}
>
> INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
> void operator delete(void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY; }
> @@ -77,5 +100,21 @@ INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
> void operator delete[](void *ptr, std::nothrow_t const&) {
> OPERATOR_DELETE_BODY;
> }
> +INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void operator delete(
> + void *ptr, std::align_val_t align) NOEXCEPT {
> + OPERATOR_DELETE_BODY;
> +}
> +INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void operator delete[](
> + void *ptr, std::align_val_t) NOEXCEPT {
> + OPERATOR_DELETE_BODY;
> +}
> +INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void operator delete(
> + void *ptr, std::align_val_t, std::nothrow_t const &) NOEXCEPT {
> + OPERATOR_DELETE_BODY;
> +}
> +INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void operator delete[](
> + void *ptr, std::align_val_t, std::nothrow_t const &) NOEXCEPT {
> + OPERATOR_DELETE_BODY;
> +}
>
> #endif // OPERATOR_NEW_BODY
> diff --git a/libsanitizer/hwasan/hwasan_report.cpp b/libsanitizer/hwasan/hwasan_report.cpp
> index 894a149775f..c0217799391 100644
> --- a/libsanitizer/hwasan/hwasan_report.cpp
> +++ b/libsanitizer/hwasan/hwasan_report.cpp
> @@ -43,12 +43,16 @@ class ScopedReport {
> }
>
> ~ScopedReport() {
> + void (*report_cb)(const char *);
> {
> BlockingMutexLock lock(&error_message_lock_);
> - if (fatal)
> - SetAbortMessage(error_message_.data());
> + report_cb = error_report_callback_;
> error_message_ptr_ = nullptr;
> }
> + if (report_cb)
> + report_cb(error_message_.data());
> + if (fatal)
> + SetAbortMessage(error_message_.data());
> if (common_flags()->print_module_map >= 2 ||
> (fatal && common_flags()->print_module_map))
> DumpProcessMap();
> @@ -66,6 +70,12 @@ class ScopedReport {
> // overwrite old trailing '\0', keep new trailing '\0' untouched.
> internal_memcpy(&(*error_message_ptr_)[old_size - 1], msg, len);
> }
> +
> + static void SetErrorReportCallback(void (*callback)(const char *)) {
> + BlockingMutexLock lock(&error_message_lock_);
> + error_report_callback_ = callback;
> + }
> +
> private:
> ScopedErrorReportLock error_report_lock_;
> InternalMmapVector<char> error_message_;
> @@ -73,10 +83,12 @@ class ScopedReport {
>
> static InternalMmapVector<char> *error_message_ptr_;
> static BlockingMutex error_message_lock_;
> + static void (*error_report_callback_)(const char *);
> };
>
> InternalMmapVector<char> *ScopedReport::error_message_ptr_;
> BlockingMutex ScopedReport::error_message_lock_;
> +void (*ScopedReport::error_report_callback_)(const char *);
>
> // If there is an active ScopedReport, append to its error message.
> void AppendToErrorMessageBuffer(const char *buffer) {
> @@ -212,7 +224,7 @@ static void PrintStackAllocations(StackAllocationsRingBuffer *sa,
>
> // We didn't find any locals. Most likely we don't have symbols, so dump
> // the information that we have for offline analysis.
> - InternalScopedString frame_desc(GetPageSizeCached() * 2);
> + InternalScopedString frame_desc;
> Printf("Previously allocated frames:\n");
> for (uptr i = 0; i < frames; i++) {
> const uptr *record_addr = &(*sa)[i];
> @@ -447,7 +459,7 @@ static void PrintTagInfoAroundAddr(tag_t *tag_ptr, uptr num_rows,
> RoundDownTo(reinterpret_cast<uptr>(tag_ptr), row_len));
> tag_t *beg_row = center_row_beg - row_len * (num_rows / 2);
> tag_t *end_row = center_row_beg + row_len * ((num_rows + 1) / 2);
> - InternalScopedString s(GetPageSizeCached() * 8);
> + InternalScopedString s;
> for (tag_t *row = beg_row; row < end_row; row += row_len) {
> s.append("%s", row == center_row_beg ? "=>" : " ");
> s.append("%p:", row);
> @@ -535,7 +547,7 @@ void ReportTailOverwritten(StackTrace *stack, uptr tagged_addr, uptr orig_size,
> GetStackTraceFromId(chunk.GetAllocStackId()).Print();
> }
>
> - InternalScopedString s(GetPageSizeCached() * 8);
> + InternalScopedString s;
> CHECK_GT(tail_size, 0U);
> CHECK_LT(tail_size, kShadowAlignment);
> u8 *tail = reinterpret_cast<u8*>(untagged_addr + orig_size);
> @@ -650,3 +662,7 @@ void ReportRegisters(uptr *frame, uptr pc) {
> }
>
> } // namespace __hwasan
> +
> +void __hwasan_set_error_report_callback(void (*callback)(const char *)) {
> + __hwasan::ScopedReport::SetErrorReportCallback(callback);
> +}
> diff --git a/libsanitizer/hwasan/hwasan_setjmp.S b/libsanitizer/hwasan/hwasan_setjmp.S
> index 0c135433194..381af63363c 100644
> --- a/libsanitizer/hwasan/hwasan_setjmp.S
> +++ b/libsanitizer/hwasan/hwasan_setjmp.S
> @@ -12,6 +12,7 @@
> //===----------------------------------------------------------------------===//
>
> #include "sanitizer_common/sanitizer_asm.h"
> +#include "builtins/assembly.h"
>
> #if HWASAN_WITH_INTERCEPTORS && defined(__aarch64__)
> #include "sanitizer_common/sanitizer_platform.h"
> @@ -34,6 +35,7 @@
> ASM_TYPE_FUNCTION(__interceptor_setjmp)
> __interceptor_setjmp:
> CFI_STARTPROC
> + BTI_C
> mov x1, #0
> b __interceptor_sigsetjmp
> CFI_ENDPROC
> @@ -46,6 +48,7 @@ ASM_SIZE(__interceptor_setjmp)
> ASM_TYPE_FUNCTION(__interceptor_setjmp_bionic)
> __interceptor_setjmp_bionic:
> CFI_STARTPROC
> + BTI_C
> mov x1, #1
> b __interceptor_sigsetjmp
> CFI_ENDPROC
> @@ -56,6 +59,7 @@ ASM_SIZE(__interceptor_setjmp_bionic)
> ASM_TYPE_FUNCTION(__interceptor_sigsetjmp)
> __interceptor_sigsetjmp:
> CFI_STARTPROC
> + BTI_C
> stp x19, x20, [x0, #0<<3]
> stp x21, x22, [x0, #2<<3]
> stp x23, x24, [x0, #4<<3]
> @@ -98,3 +102,5 @@ ALIAS __interceptor_setjmp, _setjmp
>
> // We do not need executable stack.
> NO_EXEC_STACK_DIRECTIVE
> +
> +GNU_PROPERTY_BTI_PAC
> diff --git a/libsanitizer/hwasan/hwasan_tag_mismatch_aarch64.S b/libsanitizer/hwasan/hwasan_tag_mismatch_aarch64.S
> index 08df12736bb..bcb0df42019 100644
> --- a/libsanitizer/hwasan/hwasan_tag_mismatch_aarch64.S
> +++ b/libsanitizer/hwasan/hwasan_tag_mismatch_aarch64.S
> @@ -1,4 +1,5 @@
> #include "sanitizer_common/sanitizer_asm.h"
> +#include "builtins/assembly.h"
>
> // The content of this file is AArch64-only:
> #if defined(__aarch64__)
> @@ -74,6 +75,8 @@
> .global __hwasan_tag_mismatch
> .type __hwasan_tag_mismatch, %function
> __hwasan_tag_mismatch:
> + BTI_J
> +
> // Compute the granule position one past the end of the access.
> mov x16, #1
> and x17, x1, #0xf
> @@ -106,6 +109,7 @@ __hwasan_tag_mismatch:
> .type __hwasan_tag_mismatch_v2, %function
> __hwasan_tag_mismatch_v2:
> CFI_STARTPROC
> + BTI_J
>
> // Set the CFA to be the return address for caller of __hwasan_check_*. Note
> // that we do not emit CFI predicates to describe the contents of this stack
> @@ -150,3 +154,5 @@ __hwasan_tag_mismatch_v2:
>
> // We do not need executable stack.
> NO_EXEC_STACK_DIRECTIVE
> +
> +GNU_PROPERTY_BTI_PAC
> diff --git a/libsanitizer/hwasan/hwasan_thread.cpp b/libsanitizer/hwasan/hwasan_thread.cpp
> index b81a6350c05..bb4d56abed0 100644
> --- a/libsanitizer/hwasan/hwasan_thread.cpp
> +++ b/libsanitizer/hwasan/hwasan_thread.cpp
> @@ -35,6 +35,10 @@ void Thread::InitRandomState() {
> }
>
> void Thread::Init(uptr stack_buffer_start, uptr stack_buffer_size) {
> + CHECK_EQ(0, unique_id_); // try to catch bad stack reuse
> + CHECK_EQ(0, stack_top_);
> + CHECK_EQ(0, stack_bottom_);
> +
> static u64 unique_id;
> unique_id_ = unique_id++;
> if (auto sz = flags()->heap_history_size)
> @@ -113,18 +117,21 @@ static u32 xorshift(u32 state) {
> }
>
> // Generate a (pseudo-)random non-zero tag.
> -tag_t Thread::GenerateRandomTag() {
> +tag_t Thread::GenerateRandomTag(uptr num_bits) {
> + DCHECK_GT(num_bits, 0);
> if (tagging_disabled_) return 0;
> tag_t tag;
> + const uptr tag_mask = (1ULL << num_bits) - 1;
> do {
> if (flags()->random_tags) {
> if (!random_buffer_)
> random_buffer_ = random_state_ = xorshift(random_state_);
> CHECK(random_buffer_);
> - tag = random_buffer_ & 0xFF;
> - random_buffer_ >>= 8;
> + tag = random_buffer_ & tag_mask;
> + random_buffer_ >>= num_bits;
> } else {
> - tag = random_state_ = (random_state_ + 1) & 0xFF;
> + random_state_ += 1;
> + tag = random_state_ & tag_mask;
> }
> } while (!tag);
> return tag;
> diff --git a/libsanitizer/hwasan/hwasan_thread.h b/libsanitizer/hwasan/hwasan_thread.h
> index ebcdb791fb3..1c71cab41c4 100644
> --- a/libsanitizer/hwasan/hwasan_thread.h
> +++ b/libsanitizer/hwasan/hwasan_thread.h
> @@ -42,7 +42,7 @@ class Thread {
> HeapAllocationsRingBuffer *heap_allocations() { return heap_allocations_; }
> StackAllocationsRingBuffer *stack_allocations() { return stack_allocations_; }
>
> - tag_t GenerateRandomTag();
> + tag_t GenerateRandomTag(uptr num_bits = kTagBits);
>
> void DisableTagging() { tagging_disabled_++; }
> void EnableTagging() { tagging_disabled_--; }
> @@ -74,8 +74,6 @@ class Thread {
> HeapAllocationsRingBuffer *heap_allocations_;
> StackAllocationsRingBuffer *stack_allocations_;
>
> - Thread *next_; // All live threads form a linked list.
> -
> u64 unique_id_; // counting from zero.
>
> u32 tagging_disabled_; // if non-zero, malloc uses zero tag in this thread.
> diff --git a/libsanitizer/hwasan/hwasan_thread_list.h b/libsanitizer/hwasan/hwasan_thread_list.h
> index 914b632d977..11c586314ce 100644
> --- a/libsanitizer/hwasan/hwasan_thread_list.h
> +++ b/libsanitizer/hwasan/hwasan_thread_list.h
> @@ -66,40 +66,6 @@ static uptr RingBufferSize() {
> return 0;
> }
>
> -struct ThreadListHead {
> - Thread *list_;
> -
> - ThreadListHead() : list_(nullptr) {}
> -
> - void Push(Thread *t) {
> - t->next_ = list_;
> - list_ = t;
> - }
> -
> - Thread *Pop() {
> - Thread *t = list_;
> - if (t)
> - list_ = t->next_;
> - return t;
> - }
> -
> - void Remove(Thread *t) {
> - Thread **cur = &list_;
> - while (*cur != t) cur = &(*cur)->next_;
> - CHECK(*cur && "thread not found");
> - *cur = (*cur)->next_;
> - }
> -
> - template <class CB>
> - void ForEach(CB cb) {
> - Thread *t = list_;
> - while (t) {
> - cb(t);
> - t = t->next_;
> - }
> - }
> -};
> -
> struct ThreadStats {
> uptr n_live_threads;
> uptr total_stack_size;
> @@ -120,17 +86,23 @@ class HwasanThreadList {
> }
>
> Thread *CreateCurrentThread() {
> - Thread *t;
> + Thread *t = nullptr;
> {
> - SpinMutexLock l(&list_mutex_);
> - t = free_list_.Pop();
> - if (t) {
> - uptr start = (uptr)t - ring_buffer_size_;
> - internal_memset((void *)start, 0, ring_buffer_size_ + sizeof(Thread));
> - } else {
> - t = AllocThread();
> + SpinMutexLock l(&free_list_mutex_);
> + if (!free_list_.empty()) {
> + t = free_list_.back();
> + free_list_.pop_back();
> }
> - live_list_.Push(t);
> + }
> + if (t) {
> + uptr start = (uptr)t - ring_buffer_size_;
> + internal_memset((void *)start, 0, ring_buffer_size_ + sizeof(Thread));
> + } else {
> + t = AllocThread();
> + }
> + {
> + SpinMutexLock l(&live_list_mutex_);
> + live_list_.push_back(t);
> }
> t->Init((uptr)t - ring_buffer_size_, ring_buffer_size_);
> AddThreadStats(t);
> @@ -142,13 +114,26 @@ class HwasanThreadList {
> ReleaseMemoryPagesToOS(start, start + thread_alloc_size_);
> }
>
> + void RemoveThreadFromLiveList(Thread *t) {
> + SpinMutexLock l(&live_list_mutex_);
> + for (Thread *&t2 : live_list_)
> + if (t2 == t) {
> + // To remove t2, copy the last element of the list in t2's position, and
> + // pop_back(). This works even if t2 is itself the last element.
> + t2 = live_list_.back();
> + live_list_.pop_back();
> + return;
> + }
> + CHECK(0 && "thread not found in live list");
> + }
> +
> void ReleaseThread(Thread *t) {
> RemoveThreadStats(t);
> t->Destroy();
> - SpinMutexLock l(&list_mutex_);
> - live_list_.Remove(t);
> - free_list_.Push(t);
> DontNeedThread(t);
> + RemoveThreadFromLiveList(t);
> + SpinMutexLock l(&free_list_mutex_);
> + free_list_.push_back(t);
> }
>
> Thread *GetThreadByBufferAddress(uptr p) {
> @@ -165,8 +150,8 @@ class HwasanThreadList {
>
> template <class CB>
> void VisitAllLiveThreads(CB cb) {
> - SpinMutexLock l(&list_mutex_);
> - live_list_.ForEach(cb);
> + SpinMutexLock l(&live_list_mutex_);
> + for (Thread *t : live_list_) cb(t);
> }
>
> void AddThreadStats(Thread *t) {
> @@ -188,6 +173,7 @@ class HwasanThreadList {
>
> private:
> Thread *AllocThread() {
> + SpinMutexLock l(&free_space_mutex_);
> uptr align = ring_buffer_size_ * 2;
> CHECK(IsAligned(free_space_, align));
> Thread *t = (Thread *)(free_space_ + ring_buffer_size_);
> @@ -196,14 +182,16 @@ class HwasanThreadList {
> return t;
> }
>
> + SpinMutex free_space_mutex_;
> uptr free_space_;
> uptr free_space_end_;
> uptr ring_buffer_size_;
> uptr thread_alloc_size_;
>
> - ThreadListHead free_list_;
> - ThreadListHead live_list_;
> - SpinMutex list_mutex_;
> + SpinMutex free_list_mutex_;
> + InternalMmapVector<Thread *> free_list_;
> + SpinMutex live_list_mutex_;
> + InternalMmapVector<Thread *> live_list_;
>
> ThreadStats stats_;
> SpinMutex stats_mutex_;
> diff --git a/libsanitizer/include/sanitizer/common_interface_defs.h b/libsanitizer/include/sanitizer/common_interface_defs.h
> index b4f977bf557..cd69285b8d4 100644
> --- a/libsanitizer/include/sanitizer/common_interface_defs.h
> +++ b/libsanitizer/include/sanitizer/common_interface_defs.h
> @@ -43,6 +43,9 @@ void __sanitizer_set_report_path(const char *path);
> // Tell the tools to write their reports to the provided file descriptor
> // (casted to void *).
> void __sanitizer_set_report_fd(void *fd);
> +// Get the current full report file path, if a path was specified by
> +// an earlier call to __sanitizer_set_report_path. Returns null otherwise.
> +const char *__sanitizer_get_report_path();
>
> // 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
> diff --git a/libsanitizer/include/sanitizer/dfsan_interface.h b/libsanitizer/include/sanitizer/dfsan_interface.h
> index 18b2c81a602..40f9379b557 100644
> --- a/libsanitizer/include/sanitizer/dfsan_interface.h
> +++ b/libsanitizer/include/sanitizer/dfsan_interface.h
> @@ -22,6 +22,7 @@ extern "C" {
> #endif
>
> typedef uint16_t dfsan_label;
> +typedef uint32_t dfsan_origin;
>
> /// Stores information associated with a specific label identifier. A label
> /// may be a base label created using dfsan_create_label, with associated
> @@ -63,6 +64,12 @@ void dfsan_add_label(dfsan_label label, void *addr, size_t size);
> /// value.
> dfsan_label dfsan_get_label(long data);
>
> +/// Retrieves the immediate origin associated with the given data. The returned
> +/// origin may point to another origin.
> +///
> +/// The type of 'data' is arbitrary.
> +dfsan_origin dfsan_get_origin(long data);
> +
> /// Retrieves the label associated with the data at the given address.
> dfsan_label dfsan_read_label(const void *addr, size_t size);
>
> @@ -110,6 +117,15 @@ void dfsan_weak_hook_memcmp(void *caller_pc, const void *s1, const void *s2,
> void dfsan_weak_hook_strncmp(void *caller_pc, const char *s1, const char *s2,
> size_t n, dfsan_label s1_label,
> dfsan_label s2_label, dfsan_label n_label);
> +
> +/// Prints the origin trace of the label at the address addr to stderr. It also
> +/// prints description at the beginning of the trace. If origin tracking is not
> +/// on, or the address is not labeled, it prints nothing.
> +void dfsan_print_origin_trace(const void *addr, const char *description);
> +
> +/// Retrieves the very first origin associated with the data at the given
> +/// address.
> +dfsan_origin dfsan_get_init_origin(const void *addr);
> #ifdef __cplusplus
> } // extern "C"
>
> diff --git a/libsanitizer/include/sanitizer/hwasan_interface.h b/libsanitizer/include/sanitizer/hwasan_interface.h
> index 4c9ad13aa0c..14035c05c63 100644
> --- a/libsanitizer/include/sanitizer/hwasan_interface.h
> +++ b/libsanitizer/include/sanitizer/hwasan_interface.h
> @@ -73,6 +73,9 @@ extern "C" {
> * accessed through the pointer in x, or -1 if the whole range is good. */
> intptr_t __hwasan_test_shadow(const volatile void *x, size_t size);
>
> + /* Sets the callback function to be called during HWASan error reporting. */
> + void __hwasan_set_error_report_callback(void (*callback)(const char *));
> +
> int __sanitizer_posix_memalign(void **memptr, size_t alignment, size_t size);
> void * __sanitizer_memalign(size_t alignment, size_t size);
> void * __sanitizer_aligned_alloc(size_t alignment, size_t size);
> diff --git a/libsanitizer/include/sanitizer/memprof_interface.h b/libsanitizer/include/sanitizer/memprof_interface.h
> index a7212605100..76031de4014 100644
> --- a/libsanitizer/include/sanitizer/memprof_interface.h
> +++ b/libsanitizer/include/sanitizer/memprof_interface.h
> @@ -53,6 +53,11 @@ void __memprof_print_accumulated_stats(void);
> /// \returns Default options string.
> const char *__memprof_default_options(void);
>
> +/// Prints the memory profile to the current profile file.
> +///
> +/// \returns 0 on success.
> +int __memprof_profile_dump(void);
> +
> #ifdef __cplusplus
> } // extern "C"
> #endif
> diff --git a/libsanitizer/include/sanitizer/tsan_interface.h b/libsanitizer/include/sanitizer/tsan_interface.h
> index 96b8ad58541..565aa391a9f 100644
> --- a/libsanitizer/include/sanitizer/tsan_interface.h
> +++ b/libsanitizer/include/sanitizer/tsan_interface.h
> @@ -67,6 +67,12 @@ static const unsigned __tsan_mutex_recursive_lock = 1 << 6;
> // the corresponding __tsan_mutex_post_lock annotation.
> static const unsigned __tsan_mutex_recursive_unlock = 1 << 7;
>
> +// Convenient composed constants.
> +static const unsigned __tsan_mutex_try_read_lock =
> + __tsan_mutex_read_lock | __tsan_mutex_try_lock;
> +static const unsigned __tsan_mutex_try_read_lock_failed =
> + __tsan_mutex_try_read_lock | __tsan_mutex_try_lock_failed;
> +
> // Annotate creation of a mutex.
> // Supported flags: mutex creation flags.
> void __tsan_mutex_create(void *addr, unsigned flags);
> @@ -141,7 +147,7 @@ void __tsan_external_write(void *addr, void *caller_pc, void *tag);
> // and freed by __tsan_destroy_fiber.
> // - TSAN context of current fiber or thread can be obtained
> // by calling __tsan_get_current_fiber.
> -// - __tsan_switch_to_fiber should be called immediatly before switch
> +// - __tsan_switch_to_fiber should be called immediately before switch
> // to fiber, such as call of swapcontext.
> // - Fiber name can be set by __tsan_set_fiber_name.
> void *__tsan_get_current_fiber(void);
> @@ -154,6 +160,15 @@ void __tsan_set_fiber_name(void *fiber, const char *name);
> // Do not establish a happens-before relation between fibers
> static const unsigned __tsan_switch_to_fiber_no_sync = 1 << 0;
>
> +// User-provided callback invoked on TSan initialization.
> +void __tsan_on_initialize();
> +
> +// User-provided callback invoked on TSan shutdown.
> +// `failed` - Nonzero if TSan did detect issues, zero otherwise.
> +// Return `0` if TSan should exit as if no issues were detected. Return nonzero
> +// if TSan should exit as if issues were detected.
> +int __tsan_on_finalize(int failed);
> +
> #ifdef __cplusplus
> } // extern "C"
> #endif
> diff --git a/libsanitizer/include/sanitizer/tsan_interface_atomic.h b/libsanitizer/include/sanitizer/tsan_interface_atomic.h
> index 8052bc1d56b..5e41e2256c3 100644
> --- a/libsanitizer/include/sanitizer/tsan_interface_atomic.h
> +++ b/libsanitizer/include/sanitizer/tsan_interface_atomic.h
> @@ -30,7 +30,7 @@ __extension__ typedef __int128 __tsan_atomic128;
> #endif
>
> // Part of ABI, do not change.
> -// https://github.com/llvm/llvm-project/blob/master/libcxx/include/atomic
> +// https://github.com/llvm/llvm-project/blob/main/libcxx/include/atomic
> typedef enum {
> __tsan_memory_order_relaxed,
> __tsan_memory_order_consume,
> diff --git a/libsanitizer/interception/interception_linux.cpp b/libsanitizer/interception/interception_linux.cpp
> index 6883608d44f..5111a87f0a6 100644
> --- a/libsanitizer/interception/interception_linux.cpp
> +++ b/libsanitizer/interception/interception_linux.cpp
> @@ -63,8 +63,8 @@ bool InterceptFunction(const char *name, uptr *ptr_to_real, uptr func,
> return addr && (func == wrapper);
> }
>
> -// Android and Solaris do not have dlvsym
> -#if !SANITIZER_ANDROID && !SANITIZER_SOLARIS
> +// dlvsym is a GNU extension supported by some other platforms.
> +#if SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD
> static void *GetFuncAddr(const char *name, const char *ver) {
> return dlvsym(RTLD_NEXT, name, ver);
> }
> @@ -75,7 +75,7 @@ bool InterceptFunction(const char *name, const char *ver, uptr *ptr_to_real,
> *ptr_to_real = (uptr)addr;
> return addr && (func == wrapper);
> }
> -#endif // !SANITIZER_ANDROID
> +#endif // SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD
>
> } // namespace __interception
>
> diff --git a/libsanitizer/interception/interception_linux.h b/libsanitizer/interception/interception_linux.h
> index 097375fd1c1..a08f8cb98c4 100644
> --- a/libsanitizer/interception/interception_linux.h
> +++ b/libsanitizer/interception/interception_linux.h
> @@ -35,8 +35,8 @@ bool InterceptFunction(const char *name, const char *ver, uptr *ptr_to_real,
> (::__interception::uptr) & (func), \
> (::__interception::uptr) & WRAP(func))
>
> -// Android and Solaris do not have dlvsym
> -#if !SANITIZER_ANDROID && !SANITIZER_SOLARIS
> +// dlvsym is a GNU extension supported by some other platforms.
> +#if SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD
> #define INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver) \
> ::__interception::InterceptFunction( \
> #func, symver, \
> @@ -46,7 +46,7 @@ bool InterceptFunction(const char *name, const char *ver, uptr *ptr_to_real,
> #else
> #define INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver) \
> INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func)
> -#endif // !SANITIZER_ANDROID && !SANITIZER_SOLARIS
> +#endif // SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD
>
> #endif // INTERCEPTION_LINUX_H
> #endif // SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD ||
> diff --git a/libsanitizer/interception/interception_win.cpp b/libsanitizer/interception/interception_win.cpp
> index 1a1c327e612..98bc756ae53 100644
> --- a/libsanitizer/interception/interception_win.cpp
> +++ b/libsanitizer/interception/interception_win.cpp
> @@ -136,7 +136,7 @@ namespace __interception {
> static const int kAddressLength = FIRST_32_SECOND_64(4, 8);
> static const int kJumpInstructionLength = 5;
> static const int kShortJumpInstructionLength = 2;
> -static const int kIndirectJumpInstructionLength = 6;
> +UNUSED static const int kIndirectJumpInstructionLength = 6;
> static const int kBranchLength =
> FIRST_32_SECOND_64(kJumpInstructionLength, kIndirectJumpInstructionLength);
> static const int kDirectBranchLength = kBranchLength + kAddressLength;
> @@ -165,7 +165,7 @@ static uptr GetMmapGranularity() {
> return si.dwAllocationGranularity;
> }
>
> -static uptr RoundUpTo(uptr size, uptr boundary) {
> +UNUSED static uptr RoundUpTo(uptr size, uptr boundary) {
> return (size + boundary - 1) & ~(boundary - 1);
> }
>
> @@ -309,7 +309,7 @@ struct TrampolineMemoryRegion {
> uptr max_size;
> };
>
> -static const uptr kTrampolineScanLimitRange = 1 << 31; // 2 gig
> +UNUSED static const uptr kTrampolineScanLimitRange = 1 << 31; // 2 gig
> static const int kMaxTrampolineRegion = 1024;
> static TrampolineMemoryRegion TrampolineRegions[kMaxTrampolineRegion];
>
> diff --git a/libsanitizer/lsan/lsan_allocator.cpp b/libsanitizer/lsan/lsan_allocator.cpp
> index d86c3921395..91e34ebb321 100644
> --- a/libsanitizer/lsan/lsan_allocator.cpp
> +++ b/libsanitizer/lsan/lsan_allocator.cpp
> @@ -123,14 +123,18 @@ void Deallocate(void *p) {
>
> void *Reallocate(const StackTrace &stack, void *p, uptr new_size,
> uptr alignment) {
> - RegisterDeallocation(p);
> if (new_size > max_malloc_size) {
> - allocator.Deallocate(GetAllocatorCache(), p);
> - return ReportAllocationSizeTooBig(new_size, stack);
> + ReportAllocationSizeTooBig(new_size, stack);
> + return nullptr;
> }
> - p = allocator.Reallocate(GetAllocatorCache(), p, new_size, alignment);
> - RegisterAllocation(stack, p, new_size);
> - return p;
> + RegisterDeallocation(p);
> + void *new_p =
> + allocator.Reallocate(GetAllocatorCache(), p, new_size, alignment);
> + if (new_p)
> + RegisterAllocation(stack, new_p, new_size);
> + else if (new_size != 0)
> + RegisterAllocation(stack, p, new_size);
> + return new_p;
> }
>
> void GetAllocatorCacheRange(uptr *begin, uptr *end) {
> @@ -309,6 +313,16 @@ IgnoreObjectResult IgnoreObjectLocked(const void *p) {
> return kIgnoreObjectInvalid;
> }
> }
> +
> +void GetAdditionalThreadContextPtrs(ThreadContextBase *tctx, void *ptrs) {
> + // This function can be used to treat memory reachable from `tctx` as live.
> + // This is useful for threads that have been created but not yet started.
> +
> + // This is currently a no-op because the LSan `pthread_create()` interceptor
> + // blocks until the child thread starts which keeps the thread's `arg` pointer
> + // live.
> +}
> +
> } // namespace __lsan
>
> using namespace __lsan;
> diff --git a/libsanitizer/lsan/lsan_allocator.h b/libsanitizer/lsan/lsan_allocator.h
> index 17e13cd014b..9d763789154 100644
> --- a/libsanitizer/lsan/lsan_allocator.h
> +++ b/libsanitizer/lsan/lsan_allocator.h
> @@ -50,7 +50,7 @@ struct ChunkMetadata {
> };
>
> #if defined(__mips64) || defined(__aarch64__) || defined(__i386__) || \
> - defined(__arm__)
> + defined(__arm__) || SANITIZER_RISCV64
> template <typename AddressSpaceViewTy>
> struct AP32 {
> static const uptr kSpaceBeg = 0;
> diff --git a/libsanitizer/lsan/lsan_common.cpp b/libsanitizer/lsan/lsan_common.cpp
> index 9e23aa9997a..74400d2e842 100644
> --- a/libsanitizer/lsan/lsan_common.cpp
> +++ b/libsanitizer/lsan/lsan_common.cpp
> @@ -65,8 +65,34 @@ void RegisterLsanFlags(FlagParser *parser, Flags *f) {
> if (flags()->log_threads) Report(__VA_ARGS__); \
> } while (0)
>
> -ALIGNED(64) static char suppression_placeholder[sizeof(SuppressionContext)];
> -static SuppressionContext *suppression_ctx = nullptr;
> +class LeakSuppressionContext {
> + bool parsed = false;
> + SuppressionContext context;
> + bool suppressed_stacks_sorted = true;
> + InternalMmapVector<u32> suppressed_stacks;
> +
> + Suppression *GetSuppressionForAddr(uptr addr);
> + void LazyInit();
> +
> + public:
> + LeakSuppressionContext(const char *supprression_types[],
> + int suppression_types_num)
> + : context(supprression_types, suppression_types_num) {}
> +
> + Suppression *GetSuppressionForStack(u32 stack_trace_id);
> +
> + const InternalMmapVector<u32> &GetSortedSuppressedStacks() {
> + if (!suppressed_stacks_sorted) {
> + suppressed_stacks_sorted = true;
> + SortAndDedup(suppressed_stacks);
> + }
> + return suppressed_stacks;
> + }
> + void PrintMatchedSuppressions();
> +};
> +
> +ALIGNED(64) static char suppression_placeholder[sizeof(LeakSuppressionContext)];
> +static LeakSuppressionContext *suppression_ctx = nullptr;
> static const char kSuppressionLeak[] = "leak";
> static const char *kSuppressionTypes[] = { kSuppressionLeak };
> static const char kStdSuppressions[] =
> @@ -86,14 +112,20 @@ static const char kStdSuppressions[] =
> void InitializeSuppressions() {
> CHECK_EQ(nullptr, suppression_ctx);
> suppression_ctx = new (suppression_placeholder)
> - SuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes));
> - suppression_ctx->ParseFromFile(flags()->suppressions);
> - if (&__lsan_default_suppressions)
> - suppression_ctx->Parse(__lsan_default_suppressions());
> - suppression_ctx->Parse(kStdSuppressions);
> + LeakSuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes));
> +}
> +
> +void LeakSuppressionContext::LazyInit() {
> + if (!parsed) {
> + parsed = true;
> + context.ParseFromFile(flags()->suppressions);
> + if (&__lsan_default_suppressions)
> + context.Parse(__lsan_default_suppressions());
> + context.Parse(kStdSuppressions);
> + }
> }
>
> -static SuppressionContext *GetSuppressionContext() {
> +static LeakSuppressionContext *GetSuppressionContext() {
> CHECK(suppression_ctx);
> return suppression_ctx;
> }
> @@ -221,6 +253,27 @@ extern "C" SANITIZER_WEAK_ATTRIBUTE void __libc_iterate_dynamic_tls(
> pid_t, void (*cb)(void *, void *, uptr, void *), void *);
> #endif
>
> +static void ProcessThreadRegistry(Frontier *frontier) {
> + InternalMmapVector<uptr> ptrs;
> + GetThreadRegistryLocked()->RunCallbackForEachThreadLocked(
> + GetAdditionalThreadContextPtrs, &ptrs);
> +
> + for (uptr i = 0; i < ptrs.size(); ++i) {
> + void *ptr = reinterpret_cast<void *>(ptrs[i]);
> + uptr chunk = PointsIntoChunk(ptr);
> + if (!chunk)
> + continue;
> + LsanMetadata m(chunk);
> + if (!m.allocated())
> + continue;
> +
> + // Mark as reachable and add to frontier.
> + LOG_POINTERS("Treating pointer %p from ThreadContext as reachable\n", ptr);
> + m.set_tag(kReachable);
> + frontier->push_back(chunk);
> + }
> +}
> +
> // Scans thread data (stacks and TLS) for heap pointers.
> static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
> Frontier *frontier) {
> @@ -315,15 +368,15 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
> __libc_iterate_dynamic_tls(os_id, cb, frontier);
> #else
> if (dtls && !DTLSInDestruction(dtls)) {
> - for (uptr j = 0; j < dtls->dtv_size; ++j) {
> - uptr dtls_beg = dtls->dtv[j].beg;
> - uptr dtls_end = dtls_beg + dtls->dtv[j].size;
> + ForEachDVT(dtls, [&](const DTLS::DTV &dtv, int id) {
> + uptr dtls_beg = dtv.beg;
> + uptr dtls_end = dtls_beg + dtv.size;
> if (dtls_beg < dtls_end) {
> - LOG_THREADS("DTLS %zu at %p-%p.\n", j, dtls_beg, dtls_end);
> + LOG_THREADS("DTLS %zu at %p-%p.\n", id, dtls_beg, dtls_end);
> ScanRangeForPointers(dtls_beg, dtls_end, frontier, "DTLS",
> kReachable);
> }
> - }
> + });
> } else {
> // We are handling a thread with DTLS under destruction. Log about
> // this and continue.
> @@ -332,6 +385,9 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
> #endif
> }
> }
> +
> + // Add pointers reachable from ThreadContexts
> + ProcessThreadRegistry(frontier);
> }
>
> #endif // SANITIZER_FUCHSIA
> @@ -390,6 +446,24 @@ static void MarkIndirectlyLeakedCb(uptr chunk, void *arg) {
> }
> }
>
> +static void IgnoredSuppressedCb(uptr chunk, void *arg) {
> + CHECK(arg);
> + chunk = GetUserBegin(chunk);
> + LsanMetadata m(chunk);
> + if (!m.allocated() || m.tag() == kIgnored)
> + return;
> +
> + const InternalMmapVector<u32> &suppressed =
> + *static_cast<const InternalMmapVector<u32> *>(arg);
> + uptr idx = InternalLowerBound(suppressed, m.stack_trace_id());
> + if (idx >= suppressed.size() || m.stack_trace_id() != suppressed[idx])
> + return;
> +
> + LOG_POINTERS("Suppressed: chunk %p-%p of size %zu.\n", chunk,
> + chunk + m.requested_size(), m.requested_size());
> + m.set_tag(kIgnored);
> +}
> +
> // ForEachChunk callback. If chunk is marked as ignored, adds its address to
> // frontier.
> static void CollectIgnoredCb(uptr chunk, void *arg) {
> @@ -473,6 +547,12 @@ void ProcessPC(Frontier *frontier) {
> // Sets the appropriate tag on each chunk.
> static void ClassifyAllChunks(SuspendedThreadsList const &suspended_threads,
> Frontier *frontier) {
> + const InternalMmapVector<u32> &suppressed_stacks =
> + GetSuppressionContext()->GetSortedSuppressedStacks();
> + if (!suppressed_stacks.empty()) {
> + ForEachChunk(IgnoredSuppressedCb,
> + const_cast<InternalMmapVector<u32> *>(&suppressed_stacks));
> + }
> ForEachChunk(CollectIgnoredCb, frontier);
> ProcessGlobalRegions(frontier);
> ProcessThreads(suspended_threads, frontier);
> @@ -532,18 +612,20 @@ static void CollectLeaksCb(uptr chunk, void *arg) {
> }
> }
>
> -static void PrintMatchedSuppressions() {
> +void LeakSuppressionContext::PrintMatchedSuppressions() {
> InternalMmapVector<Suppression *> matched;
> - GetSuppressionContext()->GetMatched(&matched);
> + context.GetMatched(&matched);
> if (!matched.size())
> return;
> const char *line = "-----------------------------------------------------";
> Printf("%s\n", line);
> Printf("Suppressions used:\n");
> Printf(" count bytes template\n");
> - for (uptr i = 0; i < matched.size(); i++)
> - Printf("%7zu %10zu %s\n", static_cast<uptr>(atomic_load_relaxed(
> - &matched[i]->hit_count)), matched[i]->weight, matched[i]->templ);
> + for (uptr i = 0; i < matched.size(); i++) {
> + Printf("%7zu %10zu %s\n",
> + static_cast<uptr>(atomic_load_relaxed(&matched[i]->hit_count)),
> + matched[i]->weight, matched[i]->templ);
> + }
> Printf("%s\n\n", line);
> }
>
> @@ -551,8 +633,7 @@ static void ReportIfNotSuspended(ThreadContextBase *tctx, void *arg) {
> const InternalMmapVector<tid_t> &suspended_threads =
> *(const InternalMmapVector<tid_t> *)arg;
> if (tctx->status == ThreadStatusRunning) {
> - uptr i = InternalLowerBound(suspended_threads, 0, suspended_threads.size(),
> - tctx->os_id, CompareLess<int>());
> + uptr i = InternalLowerBound(suspended_threads, tctx->os_id);
> if (i >= suspended_threads.size() || suspended_threads[i] != tctx->os_id)
> Report("Running thread %d was not suspended. False leaks are possible.\n",
> tctx->os_id);
> @@ -595,43 +676,68 @@ static void CheckForLeaksCallback(const SuspendedThreadsList &suspended_threads,
> param->success = true;
> }
>
> -static bool CheckForLeaks() {
> - if (&__lsan_is_turned_off && __lsan_is_turned_off())
> - return false;
> - EnsureMainThreadIDIsCorrect();
> - CheckForLeaksParam param;
> - LockStuffAndStopTheWorld(CheckForLeaksCallback, ¶m);
> -
> - if (!param.success) {
> - Report("LeakSanitizer has encountered a fatal error.\n");
> - Report(
> - "HINT: For debugging, try setting environment variable "
> - "LSAN_OPTIONS=verbosity=1:log_threads=1\n");
> - Report(
> - "HINT: LeakSanitizer does not work under ptrace (strace, gdb, etc)\n");
> - Die();
> - }
> - param.leak_report.ApplySuppressions();
> - uptr unsuppressed_count = param.leak_report.UnsuppressedLeakCount();
> - if (unsuppressed_count > 0) {
> +static bool PrintResults(LeakReport &report) {
> + uptr unsuppressed_count = report.UnsuppressedLeakCount();
> + if (unsuppressed_count) {
> Decorator d;
> - Printf("\n"
> - "================================================================="
> - "\n");
> + Printf(
> + "\n"
> + "================================================================="
> + "\n");
> Printf("%s", d.Error());
> Report("ERROR: LeakSanitizer: detected memory leaks\n");
> Printf("%s", d.Default());
> - param.leak_report.ReportTopLeaks(flags()->max_leaks);
> + report.ReportTopLeaks(flags()->max_leaks);
> }
> if (common_flags()->print_suppressions)
> - PrintMatchedSuppressions();
> + GetSuppressionContext()->PrintMatchedSuppressions();
> if (unsuppressed_count > 0) {
> - param.leak_report.PrintSummary();
> + report.PrintSummary();
> return true;
> }
> return false;
> }
>
> +static bool CheckForLeaks() {
> + if (&__lsan_is_turned_off && __lsan_is_turned_off())
> + return false;
> + // Inside LockStuffAndStopTheWorld we can't run symbolizer, so we can't match
> + // suppressions. However if a stack id was previously suppressed, it should be
> + // suppressed in future checks as well.
> + for (int i = 0;; ++i) {
> + EnsureMainThreadIDIsCorrect();
> + CheckForLeaksParam param;
> + LockStuffAndStopTheWorld(CheckForLeaksCallback, ¶m);
> + if (!param.success) {
> + Report("LeakSanitizer has encountered a fatal error.\n");
> + Report(
> + "HINT: For debugging, try setting environment variable "
> + "LSAN_OPTIONS=verbosity=1:log_threads=1\n");
> + Report(
> + "HINT: LeakSanitizer does not work under ptrace (strace, gdb, "
> + "etc)\n");
> + Die();
> + }
> + // No new suppressions stacks, so rerun will not help and we can report.
> + if (!param.leak_report.ApplySuppressions())
> + return PrintResults(param.leak_report);
> +
> + // No indirect leaks to report, so we are done here.
> + if (!param.leak_report.IndirectUnsuppressedLeakCount())
> + return PrintResults(param.leak_report);
> +
> + if (i >= 8) {
> + Report("WARNING: LeakSanitizer gave up on indirect leaks suppression.\n");
> + return PrintResults(param.leak_report);
> + }
> +
> + // We found a new previously unseen suppressed call stack. Rerun to make
> + // sure it does not hold indirect leaks.
> + VReport(1, "Rerun with %zu suppressed stacks.",
> + GetSuppressionContext()->GetSortedSuppressedStacks().size());
> + }
> +}
> +
> static bool has_reported_leaks = false;
> bool HasReportedLeaks() { return has_reported_leaks; }
>
> @@ -652,21 +758,20 @@ static int DoRecoverableLeakCheck() {
>
> void DoRecoverableLeakCheckVoid() { DoRecoverableLeakCheck(); }
>
> -static Suppression *GetSuppressionForAddr(uptr addr) {
> +Suppression *LeakSuppressionContext::GetSuppressionForAddr(uptr addr) {
> Suppression *s = nullptr;
>
> // Suppress by module name.
> - SuppressionContext *suppressions = GetSuppressionContext();
> if (const char *module_name =
> Symbolizer::GetOrInit()->GetModuleNameForPc(addr))
> - if (suppressions->Match(module_name, kSuppressionLeak, &s))
> + if (context.Match(module_name, kSuppressionLeak, &s))
> return s;
>
> // Suppress by file or function name.
> SymbolizedStack *frames = Symbolizer::GetOrInit()->SymbolizePC(addr);
> for (SymbolizedStack *cur = frames; cur; cur = cur->next) {
> - if (suppressions->Match(cur->info.function, kSuppressionLeak, &s) ||
> - suppressions->Match(cur->info.file, kSuppressionLeak, &s)) {
> + if (context.Match(cur->info.function, kSuppressionLeak, &s) ||
> + context.Match(cur->info.file, kSuppressionLeak, &s)) {
> break;
> }
> }
> @@ -674,12 +779,18 @@ static Suppression *GetSuppressionForAddr(uptr addr) {
> return s;
> }
>
> -static Suppression *GetSuppressionForStack(u32 stack_trace_id) {
> +Suppression *LeakSuppressionContext::GetSuppressionForStack(
> + u32 stack_trace_id) {
> + LazyInit();
> StackTrace stack = StackDepotGet(stack_trace_id);
> for (uptr i = 0; i < stack.size; i++) {
> Suppression *s = GetSuppressionForAddr(
> StackTrace::GetPreviousInstructionPc(stack.trace[i]));
> - if (s) return s;
> + if (s) {
> + suppressed_stacks_sorted = false;
> + suppressed_stacks.push_back(stack_trace_id);
> + return s;
> + }
> }
> return nullptr;
> }
> @@ -784,22 +895,27 @@ void LeakReport::PrintSummary() {
> bytes += leaks_[i].total_size;
> allocations += leaks_[i].hit_count;
> }
> - InternalScopedString summary(kMaxSummaryLength);
> + InternalScopedString summary;
> summary.append("%zu byte(s) leaked in %zu allocation(s).", bytes,
> allocations);
> ReportErrorSummary(summary.data());
> }
>
> -void LeakReport::ApplySuppressions() {
> +uptr LeakReport::ApplySuppressions() {
> + LeakSuppressionContext *suppressions = GetSuppressionContext();
> + uptr new_suppressions = false;
> for (uptr i = 0; i < leaks_.size(); i++) {
> - Suppression *s = GetSuppressionForStack(leaks_[i].stack_trace_id);
> + Suppression *s =
> + suppressions->GetSuppressionForStack(leaks_[i].stack_trace_id);
> if (s) {
> s->weight += leaks_[i].total_size;
> atomic_store_relaxed(&s->hit_count, atomic_load_relaxed(&s->hit_count) +
> leaks_[i].hit_count);
> leaks_[i].is_suppressed = true;
> + ++new_suppressions;
> }
> }
> + return new_suppressions;
> }
>
> uptr LeakReport::UnsuppressedLeakCount() {
> @@ -809,6 +925,14 @@ uptr LeakReport::UnsuppressedLeakCount() {
> return result;
> }
>
> +uptr LeakReport::IndirectUnsuppressedLeakCount() {
> + uptr result = 0;
> + for (uptr i = 0; i < leaks_.size(); i++)
> + if (!leaks_[i].is_suppressed && !leaks_[i].is_directly_leaked)
> + result++;
> + return result;
> +}
> +
> } // namespace __lsan
> #else // CAN_SANITIZE_LEAKS
> namespace __lsan {
> diff --git a/libsanitizer/lsan/lsan_common.h b/libsanitizer/lsan/lsan_common.h
> index 1fdce087b3a..fe855cf3754 100644
> --- a/libsanitizer/lsan/lsan_common.h
> +++ b/libsanitizer/lsan/lsan_common.h
> @@ -41,6 +41,8 @@
> #define CAN_SANITIZE_LEAKS 1
> #elif defined(__arm__) && SANITIZER_LINUX
> #define CAN_SANITIZE_LEAKS 1
> +#elif SANITIZER_RISCV64 && SANITIZER_LINUX
> +#define CAN_SANITIZE_LEAKS 1
> #elif SANITIZER_NETBSD || SANITIZER_FUCHSIA
> #define CAN_SANITIZE_LEAKS 1
> #else
> @@ -50,6 +52,7 @@
> namespace __sanitizer {
> class FlagParser;
> class ThreadRegistry;
> +class ThreadContextBase;
> struct DTLS;
> }
>
> @@ -63,8 +66,6 @@ enum ChunkTag {
> kIgnored = 3
> };
>
> -const u32 kInvalidTid = (u32) -1;
> -
> struct Flags {
> #define LSAN_FLAG(Type, Name, DefaultValue, Description) Type Name;
> #include "lsan_flags.inc"
> @@ -103,8 +104,9 @@ class LeakReport {
> ChunkTag tag);
> void ReportTopLeaks(uptr max_leaks);
> void PrintSummary();
> - void ApplySuppressions();
> + uptr ApplySuppressions();
> uptr UnsuppressedLeakCount();
> + uptr IndirectUnsuppressedLeakCount();
>
> private:
> void PrintReportForLeak(uptr index);
> @@ -141,6 +143,7 @@ InternalMmapVector<RootRegion> const *GetRootRegions();
> void ScanRootRegion(Frontier *frontier, RootRegion const ®ion,
> uptr region_begin, uptr region_end, bool is_readable);
> void ForEachExtraStackRangeCb(uptr begin, uptr end, void* arg);
> +void GetAdditionalThreadContextPtrs(ThreadContextBase *tctx, void *ptrs);
> // Run stoptheworld while holding any platform-specific locks, as well as the
> // allocator and thread registry locks.
> void LockStuffAndStopTheWorld(StopTheWorldCallback callback,
> diff --git a/libsanitizer/lsan/lsan_common_fuchsia.cpp b/libsanitizer/lsan/lsan_common_fuchsia.cpp
> index 3c62c9433d3..2d35fa5b1cf 100644
> --- a/libsanitizer/lsan/lsan_common_fuchsia.cpp
> +++ b/libsanitizer/lsan/lsan_common_fuchsia.cpp
> @@ -107,9 +107,7 @@ void LockStuffAndStopTheWorld(StopTheWorldCallback callback,
> auto params = static_cast<const Params *>(data);
> uptr begin = reinterpret_cast<uptr>(chunk);
> uptr end = begin + size;
> - auto i = __sanitizer::InternalLowerBound(params->allocator_caches, 0,
> - params->allocator_caches.size(),
> - begin, CompareLess<uptr>());
> + auto i = __sanitizer::InternalLowerBound(params->allocator_caches, begin);
> if (i < params->allocator_caches.size() &&
> params->allocator_caches[i] >= begin &&
> end - params->allocator_caches[i] <= sizeof(AllocatorCache)) {
> diff --git a/libsanitizer/lsan/lsan_fuchsia.h b/libsanitizer/lsan/lsan_fuchsia.h
> index 65d20ea2114..e730d8f25f2 100644
> --- a/libsanitizer/lsan/lsan_fuchsia.h
> +++ b/libsanitizer/lsan/lsan_fuchsia.h
> @@ -23,7 +23,7 @@
>
> namespace __lsan {
>
> -class ThreadContext : public ThreadContextLsanBase {
> +class ThreadContext final : public ThreadContextLsanBase {
> public:
> explicit ThreadContext(int tid);
> void OnCreated(void *arg) override;
> diff --git a/libsanitizer/lsan/lsan_interceptors.cpp b/libsanitizer/lsan/lsan_interceptors.cpp
> index bf8d316770e..90a90a56c54 100644
> --- a/libsanitizer/lsan/lsan_interceptors.cpp
> +++ b/libsanitizer/lsan/lsan_interceptors.cpp
> @@ -460,7 +460,7 @@ INTERCEPTOR(int, pthread_create, void *th, void *attr,
> if (res == 0) {
> int tid = ThreadCreate(GetCurrentThread(), *(uptr *)th,
> IsStateDetached(detached));
> - CHECK_NE(tid, 0);
> + CHECK_NE(tid, kMainTid);
> atomic_store(&p.tid, tid, memory_order_release);
> while (atomic_load(&p.tid, memory_order_acquire) != 0)
> internal_sched_yield();
> diff --git a/libsanitizer/lsan/lsan_posix.cpp b/libsanitizer/lsan/lsan_posix.cpp
> index 8e05915dd1b..5d1c3f6260d 100644
> --- a/libsanitizer/lsan/lsan_posix.cpp
> +++ b/libsanitizer/lsan/lsan_posix.cpp
> @@ -48,7 +48,7 @@ void ThreadStart(u32 tid, tid_t os_id, ThreadType thread_type) {
> OnStartedArgs args;
> uptr stack_size = 0;
> uptr tls_size = 0;
> - GetThreadStackAndTls(tid == 0, &args.stack_begin, &stack_size,
> + GetThreadStackAndTls(tid == kMainTid, &args.stack_begin, &stack_size,
> &args.tls_begin, &tls_size);
> args.stack_end = args.stack_begin + stack_size;
> args.tls_end = args.tls_begin + tls_size;
> @@ -75,8 +75,8 @@ bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end,
> }
>
> void InitializeMainThread() {
> - u32 tid = ThreadCreate(0, 0, true);
> - CHECK_EQ(tid, 0);
> + u32 tid = ThreadCreate(kMainTid, 0, true);
> + CHECK_EQ(tid, kMainTid);
> ThreadStart(tid, GetTid());
> }
>
> diff --git a/libsanitizer/lsan/lsan_thread.cpp b/libsanitizer/lsan/lsan_thread.cpp
> index 371a1f29dfe..8efb54a6fb7 100644
> --- a/libsanitizer/lsan/lsan_thread.cpp
> +++ b/libsanitizer/lsan/lsan_thread.cpp
> @@ -94,7 +94,7 @@ void ThreadJoin(u32 tid) {
> }
>
> void EnsureMainThreadIDIsCorrect() {
> - if (GetCurrentThread() == 0)
> + if (GetCurrentThread() == kMainTid)
> CurrentThreadContext()->os_id = GetTid();
> }
>
> diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_combined.h b/libsanitizer/sanitizer_common/sanitizer_allocator_combined.h
> index 33f89d6d499..eb836bc4787 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_allocator_combined.h
> +++ b/libsanitizer/sanitizer_common/sanitizer_allocator_combined.h
> @@ -35,9 +35,9 @@ class CombinedAllocator {
> secondary_.InitLinkerInitialized();
> }
>
> - void Init(s32 release_to_os_interval_ms) {
> + void Init(s32 release_to_os_interval_ms, uptr heap_start = 0) {
> stats_.Init();
> - primary_.Init(release_to_os_interval_ms);
> + primary_.Init(release_to_os_interval_ms, heap_start);
> secondary_.Init();
> }
>
> diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_primary32.h b/libsanitizer/sanitizer_common/sanitizer_allocator_primary32.h
> index b90dabbf776..fb5394cd39c 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_allocator_primary32.h
> +++ b/libsanitizer/sanitizer_common/sanitizer_allocator_primary32.h
> @@ -119,7 +119,8 @@ class SizeClassAllocator32 {
> typedef SizeClassAllocator32<Params> ThisT;
> typedef SizeClassAllocator32LocalCache<ThisT> AllocatorCache;
>
> - void Init(s32 release_to_os_interval_ms) {
> + void Init(s32 release_to_os_interval_ms, uptr heap_start = 0) {
> + CHECK(!heap_start);
> possible_regions.Init();
> internal_memset(size_class_info_array, 0, sizeof(size_class_info_array));
> }
> diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_primary64.h b/libsanitizer/sanitizer_common/sanitizer_allocator_primary64.h
> index 0a18b0c58ef..db30e138154 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_allocator_primary64.h
> +++ b/libsanitizer/sanitizer_common/sanitizer_allocator_primary64.h
> @@ -19,7 +19,7 @@ template<class SizeClassAllocator> struct SizeClassAllocator64LocalCache;
> // The template parameter Params is a class containing the actual parameters.
> //
> // Space: a portion of address space of kSpaceSize bytes starting at SpaceBeg.
> -// If kSpaceBeg is ~0 then SpaceBeg is chosen dynamically my mmap.
> +// If kSpaceBeg is ~0 then SpaceBeg is chosen dynamically by mmap.
> // Otherwise SpaceBeg=kSpaceBeg (fixed address).
> // kSpaceSize is a power of two.
> // At the beginning the entire space is mprotect-ed, then small parts of it
> @@ -69,25 +69,45 @@ class SizeClassAllocator64 {
> return base + (static_cast<uptr>(ptr32) << kCompactPtrScale);
> }
>
> - void Init(s32 release_to_os_interval_ms) {
> + // If heap_start is nonzero, assumes kSpaceSize bytes are already mapped R/W
> + // at heap_start and places the heap there. This mode requires kSpaceBeg ==
> + // ~(uptr)0.
> + void Init(s32 release_to_os_interval_ms, uptr heap_start = 0) {
> uptr TotalSpaceSize = kSpaceSize + AdditionalSize();
> - if (kUsingConstantSpaceBeg) {
> - CHECK(IsAligned(kSpaceBeg, SizeClassMap::kMaxSize));
> - CHECK_EQ(kSpaceBeg, address_range.Init(TotalSpaceSize,
> - PrimaryAllocatorName, kSpaceBeg));
> + PremappedHeap = heap_start != 0;
> + if (PremappedHeap) {
> + CHECK(!kUsingConstantSpaceBeg);
> + NonConstSpaceBeg = heap_start;
> + uptr RegionInfoSize = AdditionalSize();
> + RegionInfoSpace =
> + address_range.Init(RegionInfoSize, PrimaryAllocatorName);
> + CHECK_NE(RegionInfoSpace, ~(uptr)0);
> + CHECK_EQ(RegionInfoSpace,
> + address_range.MapOrDie(RegionInfoSpace, RegionInfoSize,
> + "SizeClassAllocator: region info"));
> + MapUnmapCallback().OnMap(RegionInfoSpace, RegionInfoSize);
> } else {
> - // Combined allocator expects that an 2^N allocation is always aligned to
> - // 2^N. For this to work, the start of the space needs to be aligned as
> - // high as the largest size class (which also needs to be a power of 2).
> - NonConstSpaceBeg = address_range.InitAligned(
> - TotalSpaceSize, SizeClassMap::kMaxSize, PrimaryAllocatorName);
> - CHECK_NE(NonConstSpaceBeg, ~(uptr)0);
> + if (kUsingConstantSpaceBeg) {
> + CHECK(IsAligned(kSpaceBeg, SizeClassMap::kMaxSize));
> + CHECK_EQ(kSpaceBeg,
> + address_range.Init(TotalSpaceSize, PrimaryAllocatorName,
> + kSpaceBeg));
> + } else {
> + // Combined allocator expects that an 2^N allocation is always aligned
> + // to 2^N. For this to work, the start of the space needs to be aligned
> + // as high as the largest size class (which also needs to be a power of
> + // 2).
> + NonConstSpaceBeg = address_range.InitAligned(
> + TotalSpaceSize, SizeClassMap::kMaxSize, PrimaryAllocatorName);
> + CHECK_NE(NonConstSpaceBeg, ~(uptr)0);
> + }
> + RegionInfoSpace = SpaceEnd();
> + MapWithCallbackOrDie(RegionInfoSpace, AdditionalSize(),
> + "SizeClassAllocator: region info");
> }
> SetReleaseToOSIntervalMs(release_to_os_interval_ms);
> - MapWithCallbackOrDie(SpaceEnd(), AdditionalSize(),
> - "SizeClassAllocator: region info");
> // Check that the RegionInfo array is aligned on the CacheLine size.
> - DCHECK_EQ(SpaceEnd() % kCacheLineSize, 0);
> + DCHECK_EQ(RegionInfoSpace % kCacheLineSize, 0);
> }
>
> s32 ReleaseToOSIntervalMs() const {
> @@ -144,6 +164,17 @@ class SizeClassAllocator64 {
> CompactPtrT *free_array = GetFreeArray(region_beg);
>
> BlockingMutexLock l(®ion->mutex);
> +#if SANITIZER_WINDOWS
> + /* On Windows unmapping of memory during __sanitizer_purge_allocator is
> + explicit and immediate, so unmapped regions must be explicitly mapped back
> + in when they are accessed again. */
> + if (region->rtoi.last_released_bytes > 0) {
> + MmapFixedOrDie(region_beg, region->mapped_user,
> + "SizeClassAllocator: region data");
> + region->rtoi.n_freed_at_last_release = 0;
> + region->rtoi.last_released_bytes = 0;
> + }
> +#endif
> if (UNLIKELY(region->num_freed_chunks < n_chunks)) {
> if (UNLIKELY(!PopulateFreeArray(stat, class_id, region,
> n_chunks - region->num_freed_chunks)))
> @@ -360,8 +391,7 @@ class SizeClassAllocator64 {
> }
> ~PackedCounterArray() {
> if (buffer) {
> - memory_mapper->UnmapPackedCounterArrayBuffer(
> - reinterpret_cast<uptr>(buffer), buffer_size);
> + memory_mapper->UnmapPackedCounterArrayBuffer(buffer, buffer_size);
> }
> }
>
> @@ -586,6 +616,11 @@ class SizeClassAllocator64 {
>
> atomic_sint32_t release_to_os_interval_ms_;
>
> + uptr RegionInfoSpace;
> +
> + // True if the user has already mapped the entire heap R/W.
> + bool PremappedHeap;
> +
> struct Stats {
> uptr n_allocated;
> uptr n_freed;
> @@ -615,7 +650,7 @@ class SizeClassAllocator64 {
>
> RegionInfo *GetRegionInfo(uptr class_id) const {
> DCHECK_LT(class_id, kNumClasses);
> - RegionInfo *regions = reinterpret_cast<RegionInfo *>(SpaceEnd());
> + RegionInfo *regions = reinterpret_cast<RegionInfo *>(RegionInfoSpace);
> return ®ions[class_id];
> }
>
> @@ -640,6 +675,9 @@ class SizeClassAllocator64 {
> }
>
> bool MapWithCallback(uptr beg, uptr size, const char *name) {
> + if (PremappedHeap)
> + return beg >= NonConstSpaceBeg &&
> + beg + size <= NonConstSpaceBeg + kSpaceSize;
> uptr mapped = address_range.Map(beg, size, name);
> if (UNLIKELY(!mapped))
> return false;
> @@ -649,11 +687,18 @@ class SizeClassAllocator64 {
> }
>
> void MapWithCallbackOrDie(uptr beg, uptr size, const char *name) {
> + if (PremappedHeap) {
> + CHECK_GE(beg, NonConstSpaceBeg);
> + CHECK_LE(beg + size, NonConstSpaceBeg + kSpaceSize);
> + return;
> + }
> CHECK_EQ(beg, address_range.MapOrDie(beg, size, name));
> MapUnmapCallback().OnMap(beg, size);
> }
>
> void UnmapWithCallbackOrDie(uptr beg, uptr size) {
> + if (PremappedHeap)
> + return;
> MapUnmapCallback().OnUnmap(beg, size);
> address_range.Unmap(beg, size);
> }
> @@ -792,17 +837,16 @@ class SizeClassAllocator64 {
> return released_bytes;
> }
>
> - uptr MapPackedCounterArrayBuffer(uptr buffer_size) {
> + void *MapPackedCounterArrayBuffer(uptr buffer_size) {
> // TODO(alekseyshl): The idea to explore is to check if we have enough
> // space between num_freed_chunks*sizeof(CompactPtrT) and
> // mapped_free_array to fit buffer_size bytes and use that space instead
> // of mapping a temporary one.
> - return reinterpret_cast<uptr>(
> - MmapOrDieOnFatalError(buffer_size, "ReleaseToOSPageCounters"));
> + return MmapOrDieOnFatalError(buffer_size, "ReleaseToOSPageCounters");
> }
>
> - void UnmapPackedCounterArrayBuffer(uptr buffer, uptr buffer_size) {
> - UnmapOrDie(reinterpret_cast<void *>(buffer), buffer_size);
> + void UnmapPackedCounterArrayBuffer(void *buffer, uptr buffer_size) {
> + UnmapOrDie(buffer, buffer_size);
> }
>
> // Releases [from, to) range of pages back to OS.
> @@ -823,6 +867,9 @@ class SizeClassAllocator64 {
>
> // Attempts to release RAM occupied by freed chunks back to OS. The region is
> // expected to be locked.
> + //
> + // TODO(morehouse): Support a callback on memory release so HWASan can release
> + // aliases as well.
> void MaybeReleaseToOS(uptr class_id, bool force) {
> RegionInfo *region = GetRegionInfo(class_id);
> const uptr chunk_size = ClassIdToSize(class_id);
> diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_size_class_map.h b/libsanitizer/sanitizer_common/sanitizer_allocator_size_class_map.h
> index 12d8c892307..c50d13303ed 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_allocator_size_class_map.h
> +++ b/libsanitizer/sanitizer_common/sanitizer_allocator_size_class_map.h
> @@ -24,7 +24,7 @@
> // E.g. with kNumBits==3 all size classes after 2^kMidSizeLog
> // look like 0b1xx0..0, where x is either 0 or 1.
> //
> -// Example: kNumBits=3, kMidSizeLog=4, kMidSizeLog=8, kMaxSizeLog=17:
> +// Example: kNumBits=3, kMinSizeLog=4, kMidSizeLog=8, kMaxSizeLog=17:
> //
> // Classes 1 - 16 correspond to sizes 16 to 256 (size = class_id * 16).
> // Next 4 classes: 256 + i * 64 (i = 1 to 4).
> diff --git a/libsanitizer/sanitizer_common/sanitizer_atomic_clang_mips.h b/libsanitizer/sanitizer_common/sanitizer_atomic_clang_mips.h
> index 59155e9883e..2b39097112d 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_atomic_clang_mips.h
> +++ b/libsanitizer/sanitizer_common/sanitizer_atomic_clang_mips.h
> @@ -41,7 +41,7 @@ inline atomic_uint64_t::Type atomic_fetch_add(volatile atomic_uint64_t *ptr,
> atomic_uint64_t::Type val,
> memory_order mo) {
> DCHECK(mo &
> - (memory_order_relaxed | memory_order_releasae | memory_order_seq_cst));
> + (memory_order_relaxed | memory_order_release | memory_order_seq_cst));
> DCHECK(!((uptr)ptr % sizeof(*ptr)));
>
> atomic_uint64_t::Type ret;
> @@ -67,7 +67,7 @@ inline bool atomic_compare_exchange_strong(volatile atomic_uint64_t *ptr,
> atomic_uint64_t::Type xchg,
> memory_order mo) {
> DCHECK(mo &
> - (memory_order_relaxed | memory_order_releasae | memory_order_seq_cst));
> + (memory_order_relaxed | memory_order_release | memory_order_seq_cst));
> DCHECK(!((uptr)ptr % sizeof(*ptr)));
>
> typedef atomic_uint64_t::Type Type;
> @@ -90,7 +90,7 @@ template <>
> inline atomic_uint64_t::Type atomic_load(const volatile atomic_uint64_t *ptr,
> memory_order mo) {
> DCHECK(mo &
> - (memory_order_relaxed | memory_order_releasae | memory_order_seq_cst));
> + (memory_order_relaxed | memory_order_release | memory_order_seq_cst));
> DCHECK(!((uptr)ptr % sizeof(*ptr)));
>
> atomic_uint64_t::Type zero = 0;
> @@ -103,7 +103,7 @@ template <>
> inline void atomic_store(volatile atomic_uint64_t *ptr, atomic_uint64_t::Type v,
> memory_order mo) {
> DCHECK(mo &
> - (memory_order_relaxed | memory_order_releasae | memory_order_seq_cst));
> + (memory_order_relaxed | memory_order_release | memory_order_seq_cst));
> DCHECK(!((uptr)ptr % sizeof(*ptr)));
>
> __spin_lock(&lock.lock);
> diff --git a/libsanitizer/sanitizer_common/sanitizer_chained_origin_depot.cpp b/libsanitizer/sanitizer_common/sanitizer_chained_origin_depot.cpp
> new file mode 100644
> index 00000000000..250ac39e130
> --- /dev/null
> +++ b/libsanitizer/sanitizer_common/sanitizer_chained_origin_depot.cpp
> @@ -0,0 +1,108 @@
> +//===-- sanitizer_chained_origin_depot.cpp --------------------------------===//
> +//
> +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
> +// See https://llvm.org/LICENSE.txt for license information.
> +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
> +//
> +//===----------------------------------------------------------------------===//
> +//
> +// A storage for chained origins.
> +//===----------------------------------------------------------------------===//
> +
> +#include "sanitizer_chained_origin_depot.h"
> +
> +namespace __sanitizer {
> +
> +bool ChainedOriginDepot::ChainedOriginDepotNode::eq(
> + u32 hash, const args_type &args) const {
> + return here_id == args.here_id && prev_id == args.prev_id;
> +}
> +
> +uptr ChainedOriginDepot::ChainedOriginDepotNode::storage_size(
> + const args_type &args) {
> + return sizeof(ChainedOriginDepotNode);
> +}
> +
> +/* This is murmur2 hash for the 64->32 bit case.
> + It does not behave all that well because the keys have a very biased
> + distribution (I've seen 7-element buckets with the table only 14% full).
> +
> + here_id is built of
> + * (1 bits) Reserved, zero.
> + * (8 bits) Part id = bits 13..20 of the hash value of here_id's key.
> + * (23 bits) Sequential number (each part has each own sequence).
> +
> + prev_id has either the same distribution as here_id (but with 3:8:21)
> + split, or one of two reserved values (-1) or (-2). Either case can
> + dominate depending on the workload.
> +*/
> +u32 ChainedOriginDepot::ChainedOriginDepotNode::hash(const args_type &args) {
> + const u32 m = 0x5bd1e995;
> + const u32 seed = 0x9747b28c;
> + const u32 r = 24;
> + u32 h = seed;
> + u32 k = args.here_id;
> + k *= m;
> + k ^= k >> r;
> + k *= m;
> + h *= m;
> + h ^= k;
> +
> + k = args.prev_id;
> + k *= m;
> + k ^= k >> r;
> + k *= m;
> + h *= m;
> + h ^= k;
> +
> + h ^= h >> 13;
> + h *= m;
> + h ^= h >> 15;
> + return h;
> +}
> +
> +bool ChainedOriginDepot::ChainedOriginDepotNode::is_valid(
> + const args_type &args) {
> + return true;
> +}
> +
> +void ChainedOriginDepot::ChainedOriginDepotNode::store(const args_type &args,
> + u32 other_hash) {
> + here_id = args.here_id;
> + prev_id = args.prev_id;
> +}
> +
> +ChainedOriginDepot::ChainedOriginDepotNode::args_type
> +ChainedOriginDepot::ChainedOriginDepotNode::load() const {
> + args_type ret = {here_id, prev_id};
> + return ret;
> +}
> +
> +ChainedOriginDepot::ChainedOriginDepotNode::Handle
> +ChainedOriginDepot::ChainedOriginDepotNode::get_handle() {
> + return Handle(this);
> +}
> +
> +ChainedOriginDepot::ChainedOriginDepot() {}
> +
> +StackDepotStats *ChainedOriginDepot::GetStats() { return depot.GetStats(); }
> +
> +bool ChainedOriginDepot::Put(u32 here_id, u32 prev_id, u32 *new_id) {
> + ChainedOriginDepotDesc desc = {here_id, prev_id};
> + bool inserted;
> + ChainedOriginDepotNode::Handle h = depot.Put(desc, &inserted);
> + *new_id = h.valid() ? h.id() : 0;
> + return inserted;
> +}
> +
> +u32 ChainedOriginDepot::Get(u32 id, u32 *other) {
> + ChainedOriginDepotDesc desc = depot.Get(id);
> + *other = desc.prev_id;
> + return desc.here_id;
> +}
> +
> +void ChainedOriginDepot::LockAll() { depot.LockAll(); }
> +
> +void ChainedOriginDepot::UnlockAll() { depot.UnlockAll(); }
> +
> +} // namespace __sanitizer
> diff --git a/libsanitizer/sanitizer_common/sanitizer_chained_origin_depot.h b/libsanitizer/sanitizer_common/sanitizer_chained_origin_depot.h
> new file mode 100644
> index 00000000000..453cdf6b544
> --- /dev/null
> +++ b/libsanitizer/sanitizer_common/sanitizer_chained_origin_depot.h
> @@ -0,0 +1,88 @@
> +//===-- sanitizer_chained_origin_depot.h ------------------------*- C++ -*-===//
> +//
> +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
> +// See https://llvm.org/LICENSE.txt for license information.
> +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
> +//
> +//===----------------------------------------------------------------------===//
> +//
> +// A storage for chained origins.
> +//===----------------------------------------------------------------------===//
> +
> +#ifndef SANITIZER_CHAINED_ORIGIN_DEPOT_H
> +#define SANITIZER_CHAINED_ORIGIN_DEPOT_H
> +
> +#include "sanitizer_common.h"
> +#include "sanitizer_stackdepotbase.h"
> +
> +namespace __sanitizer {
> +
> +class ChainedOriginDepot {
> + public:
> + ChainedOriginDepot();
> +
> + // Gets the statistic of the origin chain storage.
> + StackDepotStats *GetStats();
> +
> + // Stores a chain with StackDepot ID here_id and previous chain ID prev_id.
> + // If successful, returns true and the new chain id new_id.
> + // If the same element already exists, returns false and sets new_id to the
> + // existing ID.
> + bool Put(u32 here_id, u32 prev_id, u32 *new_id);
> +
> + // Retrieves the stored StackDepot ID for the given origin ID.
> + u32 Get(u32 id, u32 *other);
> +
> + void LockAll();
> + void UnlockAll();
> +
> + private:
> + struct ChainedOriginDepotDesc {
> + u32 here_id;
> + u32 prev_id;
> + };
> +
> + struct ChainedOriginDepotNode {
> + ChainedOriginDepotNode *link;
> + u32 id;
> + u32 here_id;
> + u32 prev_id;
> +
> + typedef ChainedOriginDepotDesc args_type;
> +
> + bool eq(u32 hash, const args_type &args) const;
> +
> + static uptr storage_size(const args_type &args);
> +
> + static u32 hash(const args_type &args);
> +
> + static bool is_valid(const args_type &args);
> +
> + void store(const args_type &args, u32 other_hash);
> +
> + args_type load() const;
> +
> + struct Handle {
> + ChainedOriginDepotNode *node_;
> + Handle() : node_(nullptr) {}
> + explicit Handle(ChainedOriginDepotNode *node) : node_(node) {}
> + bool valid() { return node_; }
> + u32 id() { return node_->id; }
> + int here_id() { return node_->here_id; }
> + int prev_id() { return node_->prev_id; }
> + };
> +
> + Handle get_handle();
> +
> + typedef Handle handle_type;
> + };
> +
> + StackDepotBase<ChainedOriginDepotNode, 4, 20> depot;
> +
> + ChainedOriginDepot(const ChainedOriginDepot &) = delete;
> + void operator=(const ChainedOriginDepot &) = delete;
> +};
> +
> +} // namespace __sanitizer
> +
> +#endif // SANITIZER_CHAINED_ORIGIN_DEPOT_H
> diff --git a/libsanitizer/sanitizer_common/sanitizer_common.cpp b/libsanitizer/sanitizer_common/sanitizer_common.cpp
> index 87efda5bd37..33960d94a2f 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_common.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_common.cpp
> @@ -87,7 +87,7 @@ const char *StripModuleName(const char *module) {
> void ReportErrorSummary(const char *error_message, const char *alt_tool_name) {
> if (!common_flags()->print_summary)
> return;
> - InternalScopedString buff(kMaxSummaryLength);
> + InternalScopedString buff;
> buff.append("SUMMARY: %s: %s",
> alt_tool_name ? alt_tool_name : SanitizerToolName, error_message);
> __sanitizer_report_error_summary(buff.data());
> @@ -274,6 +274,14 @@ uptr ReadBinaryNameCached(/*out*/char *buf, uptr buf_len) {
> return name_len;
> }
>
> +uptr ReadBinaryDir(/*out*/ char *buf, uptr buf_len) {
> + ReadBinaryNameCached(buf, buf_len);
> + const char *exec_name_pos = StripModuleName(buf);
> + uptr name_len = exec_name_pos - buf;
> + buf[name_len] = '\0';
> + return name_len;
> +}
> +
> #if !SANITIZER_GO
> void PrintCmdline() {
> char **argv = GetArgv();
> diff --git a/libsanitizer/sanitizer_common/sanitizer_common.h b/libsanitizer/sanitizer_common/sanitizer_common.h
> index bce24d68045..7b65dd7dfb8 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_common.h
> +++ b/libsanitizer/sanitizer_common/sanitizer_common.h
> @@ -44,7 +44,7 @@ const uptr kMaxPathLength = 4096;
>
> const uptr kMaxThreadStackSize = 1 << 30; // 1Gb
>
> -static const uptr kErrorMessageBufferSize = 1 << 16;
> +const uptr kErrorMessageBufferSize = 1 << 16;
>
> // Denotes fake PC values that come from JIT/JAVA/etc.
> // For such PC values __tsan_symbolize_external_ex() will be called.
> @@ -135,6 +135,15 @@ void UnmapFromTo(uptr from, uptr to);
> uptr MapDynamicShadow(uptr shadow_size_bytes, uptr shadow_scale,
> uptr min_shadow_base_alignment, uptr &high_mem_end);
>
> +// Let S = max(shadow_size, num_aliases * alias_size, ring_buffer_size).
> +// Reserves 2*S bytes of address space to the right of the returned address and
> +// ring_buffer_size bytes to the left. The returned address is aligned to 2*S.
> +// Also creates num_aliases regions of accessible memory starting at offset S
> +// from the returned address. Each region has size alias_size and is backed by
> +// the same physical memory.
> +uptr MapDynamicShadowAndAliases(uptr shadow_size, uptr alias_size,
> + uptr num_aliases, uptr ring_buffer_size);
> +
> // Reserve memory range [beg, end]. If madvise_shadow is true then apply
> // madvise (e.g. hugepages, core dumping) requested by options.
> void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name,
> @@ -248,6 +257,7 @@ const char *StripModuleName(const char *module);
> // OS
> uptr ReadBinaryName(/*out*/char *buf, uptr buf_len);
> uptr ReadBinaryNameCached(/*out*/char *buf, uptr buf_len);
> +uptr ReadBinaryDir(/*out*/ char *buf, uptr buf_len);
> uptr ReadLongProcessName(/*out*/ char *buf, uptr buf_len);
> const char *GetProcessName();
> void UpdateProcessName();
> @@ -294,8 +304,8 @@ void NORETURN ReportMmapFailureAndDie(uptr size, const char *mem_type,
> const char *mmap_type, error_t err,
> bool raw_report = false);
>
> -// Specific tools may override behavior of "Die" and "CheckFailed" functions
> -// to do tool-specific job.
> +// Specific tools may override behavior of "Die" function to do tool-specific
> +// job.
> typedef void (*DieCallbackType)(void);
>
> // It's possible to add several callbacks that would be run when "Die" is
> @@ -307,9 +317,7 @@ bool RemoveDieCallback(DieCallbackType callback);
>
> void SetUserDieCallback(DieCallbackType callback);
>
> -typedef void (*CheckFailedCallbackType)(const char *, int, const char *,
> - u64, u64);
> -void SetCheckFailedCallback(CheckFailedCallbackType callback);
> +void SetCheckUnwindCallback(void (*callback)());
>
> // Callback will be called if soft_rss_limit_mb is given and the limit is
> // exceeded (exceeded==true) or if rss went down below the limit
> @@ -343,8 +351,6 @@ void ReportDeadlySignal(const SignalContext &sig, u32 tid,
> void SetAlternateSignalStack();
> void UnsetAlternateSignalStack();
>
> -// 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.
> @@ -441,8 +447,14 @@ inline uptr Log2(uptr x) {
>
> // Don't use std::min, std::max or std::swap, to minimize dependency
> // on libstdc++.
> -template<class T> T Min(T a, T b) { return a < b ? a : b; }
> -template<class T> T Max(T a, T b) { return a > b ? a : b; }
> +template <class T>
> +constexpr T Min(T a, T b) {
> + return a < b ? a : b;
> +}
> +template <class T>
> +constexpr T Max(T a, T b) {
> + return a > b ? a : b;
> +}
> template<class T> void Swap(T& a, T& b) {
> T tmp = a;
> a = b;
> @@ -467,6 +479,7 @@ inline int ToLower(int c) {
> template<typename T>
> class InternalMmapVectorNoCtor {
> public:
> + using value_type = T;
> void Initialize(uptr initial_capacity) {
> capacity_bytes_ = 0;
> size_ = 0;
> @@ -590,21 +603,21 @@ class InternalMmapVector : public InternalMmapVectorNoCtor<T> {
> InternalMmapVector &operator=(InternalMmapVector &&) = delete;
> };
>
> -class InternalScopedString : public InternalMmapVector<char> {
> +class InternalScopedString {
> public:
> - explicit InternalScopedString(uptr max_length)
> - : InternalMmapVector<char>(max_length), length_(0) {
> - (*this)[0] = '\0';
> - }
> - uptr length() { return length_; }
> + InternalScopedString() : buffer_(1) { buffer_[0] = '\0'; }
> +
> + uptr length() const { return buffer_.size() - 1; }
> void clear() {
> - (*this)[0] = '\0';
> - length_ = 0;
> + buffer_.resize(1);
> + buffer_[0] = '\0';
> }
> void append(const char *format, ...);
> + const char *data() const { return buffer_.data(); }
> + char *data() { return buffer_.data(); }
>
> private:
> - uptr length_;
> + InternalMmapVector<char> buffer_;
> };
>
> template <class T>
> @@ -651,9 +664,13 @@ void Sort(T *v, uptr size, Compare comp = {}) {
>
> // Works like std::lower_bound: finds the first element that is not less
> // than the val.
> -template <class Container, class Value, class Compare>
> -uptr InternalLowerBound(const Container &v, uptr first, uptr last,
> - const Value &val, Compare comp) {
> +template <class Container,
> + class Compare = CompareLess<typename Container::value_type>>
> +uptr InternalLowerBound(const Container &v,
> + const typename Container::value_type &val,
> + Compare comp = {}) {
> + uptr first = 0;
> + uptr last = v.size();
> while (last > first) {
> uptr mid = (first + last) / 2;
> if (comp(v[mid], val))
> @@ -677,6 +694,27 @@ enum ModuleArch {
> kModuleArchRISCV64
> };
>
> +// Sorts and removes duplicates from the container.
> +template <class Container,
> + class Compare = CompareLess<typename Container::value_type>>
> +void SortAndDedup(Container &v, Compare comp = {}) {
> + Sort(v.data(), v.size(), comp);
> + uptr size = v.size();
> + if (size < 2)
> + return;
> + uptr last = 0;
> + for (uptr i = 1; i < size; ++i) {
> + if (comp(v[last], v[i])) {
> + ++last;
> + if (last != i)
> + v[last] = v[i];
> + } else {
> + CHECK(!comp(v[i], v[last]));
> + }
> + }
> + v.resize(last + 1);
> +}
> +
> // Opens the file 'file_name" and reads up to 'max_len' bytes.
> // The resulting buffer is mmaped and stored in '*buff'.
> // Returns true if file was successfully opened and read.
> diff --git a/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc b/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc
> index 2f2787e283a..7867fccde39 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc
> +++ b/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc
> @@ -239,7 +239,7 @@ extern const short *_tolower_tab_;
> COMMON_INTERCEPT_FUNCTION(fn)
> #endif
>
> -#ifdef __GLIBC__
> +#if SANITIZER_GLIBC
> // If we could not find the versioned symbol, fall back to an unversioned
> // lookup. This is needed to work around a GLibc bug that causes dlsym
> // with RTLD_NEXT to return the oldest versioned symbol.
> @@ -2195,6 +2195,7 @@ INTERCEPTOR(int, clock_gettime, u32 clk_id, void *tp) {
> }
> return res;
> }
> +#if SANITIZER_GLIBC
> namespace __sanitizer {
> extern "C" {
> int real_clock_gettime(u32 clk_id, void *tp) {
> @@ -2204,6 +2205,7 @@ int real_clock_gettime(u32 clk_id, void *tp) {
> }
> } // extern "C"
> } // namespace __sanitizer
> +#endif
> INTERCEPTOR(int, clock_settime, u32 clk_id, const void *tp) {
> void *ctx;
> COMMON_INTERCEPTOR_ENTER(ctx, clock_settime, clk_id, tp);
> @@ -3355,7 +3357,7 @@ INTERCEPTOR(char *, setlocale, int category, char *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);
> + COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, REAL(strlen)(res) + 1);
> unpoison_ctype_arrays(ctx);
> }
> return res;
> @@ -4030,7 +4032,7 @@ INTERCEPTOR(int, sigwait, __sanitizer_sigset_t *set, int *sig) {
> // FIXME: under ASan the call below may write to freed memory and corrupt
> // its metadata. See
> // https://github.com/google/sanitizers/issues/321.
> - int res = REAL(sigwait)(set, sig);
> + int res = COMMON_INTERCEPTOR_BLOCK_REAL(sigwait)(set, sig);
> if (!res && sig) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sig, sizeof(*sig));
> return res;
> }
> @@ -4047,7 +4049,7 @@ INTERCEPTOR(int, sigwaitinfo, __sanitizer_sigset_t *set, void *info) {
> // FIXME: under ASan the call below may write to freed memory and corrupt
> // its metadata. See
> // https://github.com/google/sanitizers/issues/321.
> - int res = REAL(sigwaitinfo)(set, info);
> + int res = COMMON_INTERCEPTOR_BLOCK_REAL(sigwaitinfo)(set, info);
> if (res > 0 && info) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, info, siginfo_t_sz);
> return res;
> }
> @@ -4066,7 +4068,7 @@ INTERCEPTOR(int, sigtimedwait, __sanitizer_sigset_t *set, void *info,
> // FIXME: under ASan the call below may write to freed memory and corrupt
> // its metadata. See
> // https://github.com/google/sanitizers/issues/321.
> - int res = REAL(sigtimedwait)(set, info, timeout);
> + int res = COMMON_INTERCEPTOR_BLOCK_REAL(sigtimedwait)(set, info, timeout);
> if (res > 0 && info) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, info, siginfo_t_sz);
> return res;
> }
> @@ -5995,6 +5997,9 @@ void unpoison_file(__sanitizer_FILE *fp) {
> if (fp->_IO_read_base && fp->_IO_read_base < fp->_IO_read_end)
> COMMON_INTERCEPTOR_INITIALIZE_RANGE(fp->_IO_read_base,
> fp->_IO_read_end - fp->_IO_read_base);
> + if (fp->_IO_write_base && fp->_IO_write_base < fp->_IO_write_end)
> + COMMON_INTERCEPTOR_INITIALIZE_RANGE(fp->_IO_write_base,
> + fp->_IO_write_end - fp->_IO_write_base);
> #endif
> #endif // SANITIZER_HAS_STRUCT_FILE
> }
> @@ -6221,6 +6226,8 @@ INTERCEPTOR(void, _obstack_newchunk, __sanitizer_obstack *obstack, int length) {
> INTERCEPTOR(int, fflush, __sanitizer_FILE *fp) {
> void *ctx;
> COMMON_INTERCEPTOR_ENTER(ctx, fflush, fp);
> + if (fp)
> + unpoison_file(fp);
> int res = REAL(fflush)(fp);
> // FIXME: handle fp == NULL
> if (fp) {
> @@ -6240,6 +6247,8 @@ INTERCEPTOR(int, fclose, __sanitizer_FILE *fp) {
> COMMON_INTERCEPTOR_ENTER(ctx, fclose, fp);
> COMMON_INTERCEPTOR_FILE_CLOSE(ctx, fp);
> const FileMetadata *m = GetInterceptorMetadata(fp);
> + if (fp)
> + unpoison_file(fp);
> int res = REAL(fclose)(fp);
> if (m) {
> COMMON_INTERCEPTOR_INITIALIZE_RANGE(*m->addr, *m->size);
> diff --git a/libsanitizer/sanitizer_common/sanitizer_common_interceptors_ioctl.inc b/libsanitizer/sanitizer_common/sanitizer_common_interceptors_ioctl.inc
> index 490a04b2181..7f181258eab 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_common_interceptors_ioctl.inc
> +++ b/libsanitizer/sanitizer_common/sanitizer_common_interceptors_ioctl.inc
> @@ -330,13 +330,17 @@ static void ioctl_table_fill() {
> _(SOUND_PCM_WRITE_CHANNELS, WRITE, sizeof(int));
> _(SOUND_PCM_WRITE_FILTER, WRITE, sizeof(int));
> _(TCFLSH, NONE, 0);
> +#if SANITIZER_GLIBC
> _(TCGETA, WRITE, struct_termio_sz);
> +#endif
> _(TCGETS, WRITE, struct_termios_sz);
> _(TCSBRK, NONE, 0);
> _(TCSBRKP, NONE, 0);
> +#if SANITIZER_GLIBC
> _(TCSETA, READ, struct_termio_sz);
> _(TCSETAF, READ, struct_termio_sz);
> _(TCSETAW, READ, struct_termio_sz);
> +#endif
> _(TCSETS, READ, struct_termios_sz);
> _(TCSETSF, READ, struct_termios_sz);
> _(TCSETSW, READ, struct_termios_sz);
> @@ -364,7 +368,7 @@ static void ioctl_table_fill() {
> _(VT_WAITACTIVE, NONE, 0);
> #endif
>
> -#if SANITIZER_LINUX && !SANITIZER_ANDROID
> +#if SANITIZER_GLIBC
> // _(SIOCDEVPLIP, WRITE, struct_ifreq_sz); // the same as EQL_ENSLAVE
> _(CYGETDEFTHRESH, WRITE, sizeof(int));
> _(CYGETDEFTIMEOUT, WRITE, sizeof(int));
> diff --git a/libsanitizer/sanitizer_common/sanitizer_common_interceptors_vfork_aarch64.inc.S b/libsanitizer/sanitizer_common/sanitizer_common_interceptors_vfork_aarch64.inc.S
> index 20f42f1ea94..72e482754b6 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_common_interceptors_vfork_aarch64.inc.S
> +++ b/libsanitizer/sanitizer_common/sanitizer_common_interceptors_vfork_aarch64.inc.S
> @@ -1,6 +1,7 @@
> #if defined(__aarch64__) && defined(__linux__)
>
> #include "sanitizer_common/sanitizer_asm.h"
> +#include "builtins/assembly.h"
>
> ASM_HIDDEN(COMMON_INTERCEPTOR_SPILL_AREA)
>
> @@ -9,6 +10,7 @@ ASM_HIDDEN(COMMON_INTERCEPTOR_SPILL_AREA)
> ASM_TYPE_FUNCTION(ASM_WRAPPER_NAME(vfork))
> ASM_WRAPPER_NAME(vfork):
> // Save x30 in the off-stack spill area.
> + hint #25 // paciasp
> stp xzr, x30, [sp, #-16]!
> bl COMMON_INTERCEPTOR_SPILL_AREA
> ldp xzr, x30, [sp], 16
> @@ -33,6 +35,7 @@ ASM_WRAPPER_NAME(vfork):
> bl COMMON_INTERCEPTOR_SPILL_AREA
> ldr x30, [x0]
> ldp x0, xzr, [sp], 16
> + hint #29 // autiasp
>
> ret
> ASM_SIZE(vfork)
> @@ -40,4 +43,6 @@ ASM_SIZE(vfork)
> .weak vfork
> .set vfork, ASM_WRAPPER_NAME(vfork)
>
> +GNU_PROPERTY_BTI_PAC
> +
> #endif
> diff --git a/libsanitizer/sanitizer_common/sanitizer_common_interface.inc b/libsanitizer/sanitizer_common/sanitizer_common_interface.inc
> index c78b6e10b68..932e5478616 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_common_interface.inc
> +++ b/libsanitizer/sanitizer_common/sanitizer_common_interface.inc
> @@ -13,6 +13,7 @@ INTERFACE_FUNCTION(__sanitizer_contiguous_container_find_bad_address)
> INTERFACE_FUNCTION(__sanitizer_set_death_callback)
> INTERFACE_FUNCTION(__sanitizer_set_report_path)
> INTERFACE_FUNCTION(__sanitizer_set_report_fd)
> +INTERFACE_FUNCTION(__sanitizer_get_report_path)
> INTERFACE_FUNCTION(__sanitizer_verify_contiguous_container)
> INTERFACE_WEAK_FUNCTION(__sanitizer_on_print)
> INTERFACE_WEAK_FUNCTION(__sanitizer_report_error_summary)
> diff --git a/libsanitizer/sanitizer_common/sanitizer_common_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_common_libcdep.cpp
> index 047c5a17ea6..1037938f3d3 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_common_libcdep.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_common_libcdep.cpp
> @@ -92,14 +92,13 @@ void *BackgroundThread(void *arg) {
> #endif
>
> void WriteToSyslog(const char *msg) {
> - InternalScopedString msg_copy(kErrorMessageBufferSize);
> + InternalScopedString msg_copy;
> msg_copy.append("%s", msg);
> - char *p = msg_copy.data();
> - char *q;
> + const char *p = msg_copy.data();
>
> // Print one line at a time.
> // syslog, at least on Android, has an implicit message length limit.
> - while ((q = internal_strchr(p, '\n'))) {
> + while (char* q = internal_strchr(p, '\n')) {
> *q = '\0';
> WriteOneLineToSyslog(p);
> p = q + 1;
> diff --git a/libsanitizer/sanitizer_common/sanitizer_file.cpp b/libsanitizer/sanitizer_common/sanitizer_file.cpp
> index 7cce60906b7..0b92dccde4a 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_file.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_file.cpp
> @@ -58,6 +58,9 @@ void ReportFile::ReopenIfNecessary() {
> } else {
> internal_snprintf(full_path, kMaxPathLength, "%s.%zu", path_prefix, pid);
> }
> + if (common_flags()->log_suffix) {
> + internal_strlcat(full_path, common_flags()->log_suffix, kMaxPathLength);
> + }
> error_t err;
> fd = OpenFile(full_path, WrOnly, &err);
> if (fd == kInvalidFd) {
> @@ -95,6 +98,12 @@ void ReportFile::SetReportPath(const char *path) {
> }
> }
>
> +const char *ReportFile::GetReportPath() {
> + SpinMutexLock l(mu);
> + ReopenIfNecessary();
> + return full_path;
> +}
> +
> bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size,
> uptr *read_len, uptr max_len, error_t *errno_p) {
> *buff = nullptr;
> @@ -213,6 +222,10 @@ void __sanitizer_set_report_fd(void *fd) {
> report_file.fd = (fd_t)reinterpret_cast<uptr>(fd);
> report_file.fd_pid = internal_getpid();
> }
> +
> +const char *__sanitizer_get_report_path() {
> + return report_file.GetReportPath();
> +}
> } // extern "C"
>
> #endif // !SANITIZER_FUCHSIA
> diff --git a/libsanitizer/sanitizer_common/sanitizer_file.h b/libsanitizer/sanitizer_common/sanitizer_file.h
> index 26681f0493d..08671ab67d0 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_file.h
> +++ b/libsanitizer/sanitizer_common/sanitizer_file.h
> @@ -26,6 +26,7 @@ struct ReportFile {
> void Write(const char *buffer, uptr length);
> bool SupportsColors();
> void SetReportPath(const char *path);
> + const char *GetReportPath();
>
> // Don't use fields directly. They are only declared public to allow
> // aggregate initialization.
> diff --git a/libsanitizer/sanitizer_common/sanitizer_flags.cpp b/libsanitizer/sanitizer_common/sanitizer_flags.cpp
> index 21048be7304..d52e96a7c38 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_flags.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_flags.cpp
> @@ -35,6 +35,7 @@ void CommonFlags::CopyFrom(const CommonFlags &other) {
> // Copy the string from "s" to "out", making the following substitutions:
> // %b = binary basename
> // %p = pid
> +// %d = binary directory
> void SubstituteForFlagValue(const char *s, char *out, uptr out_size) {
> char *out_end = out + out_size;
> while (*s && out < out_end - 1) {
> @@ -64,6 +65,12 @@ void SubstituteForFlagValue(const char *s, char *out, uptr out_size) {
> s += 2; // skip "%p"
> break;
> }
> + case 'd': {
> + uptr len = ReadBinaryDir(out, out_end - out);
> + out += len;
> + s += 2; // skip "%d"
> + break;
> + }
> default:
> *out++ = *s++;
> break;
> diff --git a/libsanitizer/sanitizer_common/sanitizer_flags.inc b/libsanitizer/sanitizer_common/sanitizer_flags.inc
> index cfb5822645f..3bc44c6b1eb 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_flags.inc
> +++ b/libsanitizer/sanitizer_common/sanitizer_flags.inc
> @@ -59,6 +59,8 @@ COMMON_FLAG(
> bool, log_exe_name, false,
> "Mention name of executable when reporting error and "
> "append executable name to logs (as in \"log_path.exe_name.pid\").")
> +COMMON_FLAG(const char *, log_suffix, nullptr,
> + "String to append to log file name, e.g. \".txt\".")
> COMMON_FLAG(
> bool, log_to_syslog, (bool)SANITIZER_ANDROID || (bool)SANITIZER_MAC,
> "Write all sanitizer output to syslog in addition to other means of "
> diff --git a/libsanitizer/sanitizer_common/sanitizer_fuchsia.cpp b/libsanitizer/sanitizer_common/sanitizer_fuchsia.cpp
> index 7200ffdac0f..4f692f99c20 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_fuchsia.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_fuchsia.cpp
> @@ -14,7 +14,6 @@
> #include "sanitizer_fuchsia.h"
> #if SANITIZER_FUCHSIA
>
> -#include <limits.h>
> #include <pthread.h>
> #include <stdlib.h>
> #include <unistd.h>
> @@ -69,9 +68,7 @@ uptr internal_getpid() {
> return pid;
> }
>
> -int internal_dlinfo(void *handle, int request, void *p) {
> - UNIMPLEMENTED();
> -}
> +int internal_dlinfo(void *handle, int request, void *p) { UNIMPLEMENTED(); }
>
> uptr GetThreadSelf() { return reinterpret_cast<uptr>(thrd_current()); }
>
> @@ -153,9 +150,9 @@ void BlockingMutex::CheckLocked() {
> CHECK_NE(MtxUnlocked, atomic_load(m, memory_order_relaxed));
> }
>
> -uptr GetPageSize() { return PAGE_SIZE; }
> +uptr GetPageSize() { return _zx_system_get_page_size(); }
>
> -uptr GetMmapGranularity() { return PAGE_SIZE; }
> +uptr GetMmapGranularity() { return _zx_system_get_page_size(); }
>
> sanitizer_shadow_bounds_t ShadowBounds;
>
> @@ -168,7 +165,7 @@ uptr GetMaxVirtualAddress() { return GetMaxUserVirtualAddress(); }
>
> static void *DoAnonymousMmapOrDie(uptr size, const char *mem_type,
> bool raw_report, bool die_for_nomem) {
> - size = RoundUpTo(size, PAGE_SIZE);
> + size = RoundUpTo(size, GetPageSize());
>
> zx_handle_t vmo;
> zx_status_t status = _zx_vmo_create(size, 0, &vmo);
> @@ -214,15 +211,14 @@ void *MmapOrDieOnFatalError(uptr size, const char *mem_type) {
>
> uptr ReservedAddressRange::Init(uptr init_size, const char *name,
> uptr fixed_addr) {
> - init_size = RoundUpTo(init_size, PAGE_SIZE);
> + init_size = RoundUpTo(init_size, GetPageSize());
> DCHECK_EQ(os_handle_, ZX_HANDLE_INVALID);
> uintptr_t base;
> zx_handle_t vmar;
> - zx_status_t status =
> - _zx_vmar_allocate(
> - _zx_vmar_root_self(),
> - ZX_VM_CAN_MAP_READ | ZX_VM_CAN_MAP_WRITE | ZX_VM_CAN_MAP_SPECIFIC,
> - 0, init_size, &vmar, &base);
> + zx_status_t status = _zx_vmar_allocate(
> + _zx_vmar_root_self(),
> + ZX_VM_CAN_MAP_READ | ZX_VM_CAN_MAP_WRITE | ZX_VM_CAN_MAP_SPECIFIC, 0,
> + init_size, &vmar, &base);
> if (status != ZX_OK)
> ReportMmapFailureAndDie(init_size, name, "zx_vmar_allocate", status);
> base_ = reinterpret_cast<void *>(base);
> @@ -236,7 +232,7 @@ uptr ReservedAddressRange::Init(uptr init_size, const char *name,
> static uptr DoMmapFixedOrDie(zx_handle_t vmar, uptr fixed_addr, uptr map_size,
> void *base, const char *name, bool die_for_nomem) {
> uptr offset = fixed_addr - reinterpret_cast<uptr>(base);
> - map_size = RoundUpTo(map_size, PAGE_SIZE);
> + map_size = RoundUpTo(map_size, GetPageSize());
> zx_handle_t vmo;
> zx_status_t status = _zx_vmo_create(map_size, 0, &vmo);
> if (status != ZX_OK) {
> @@ -264,19 +260,19 @@ static uptr DoMmapFixedOrDie(zx_handle_t vmar, uptr fixed_addr, uptr map_size,
>
> uptr ReservedAddressRange::Map(uptr fixed_addr, uptr map_size,
> const char *name) {
> - return DoMmapFixedOrDie(os_handle_, fixed_addr, map_size, base_,
> - name_, false);
> + return DoMmapFixedOrDie(os_handle_, fixed_addr, map_size, base_, name_,
> + false);
> }
>
> uptr ReservedAddressRange::MapOrDie(uptr fixed_addr, uptr map_size,
> const char *name) {
> - return DoMmapFixedOrDie(os_handle_, fixed_addr, map_size, base_,
> - name_, true);
> + return DoMmapFixedOrDie(os_handle_, fixed_addr, map_size, base_, name_, true);
> }
>
> void UnmapOrDieVmar(void *addr, uptr size, zx_handle_t target_vmar) {
> - if (!addr || !size) return;
> - size = RoundUpTo(size, PAGE_SIZE);
> + if (!addr || !size)
> + return;
> + size = RoundUpTo(size, GetPageSize());
>
> zx_status_t status =
> _zx_vmar_unmap(target_vmar, reinterpret_cast<uintptr_t>(addr), size);
> @@ -316,7 +312,7 @@ void *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name) {
>
> void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment,
> const char *mem_type) {
> - CHECK_GE(size, PAGE_SIZE);
> + CHECK_GE(size, GetPageSize());
> CHECK(IsPowerOfTwo(size));
> CHECK(IsPowerOfTwo(alignment));
>
> @@ -356,7 +352,8 @@ void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment,
> _zx_vmar_root_self(),
> ZX_VM_PERM_READ | ZX_VM_PERM_WRITE | ZX_VM_SPECIFIC_OVERWRITE,
> addr - info.base, vmo, 0, size, &new_addr);
> - if (status == ZX_OK) CHECK_EQ(new_addr, addr);
> + if (status == ZX_OK)
> + CHECK_EQ(new_addr, addr);
> }
> }
> if (status == ZX_OK && addr != map_addr)
> @@ -381,9 +378,18 @@ void UnmapOrDie(void *addr, uptr size) {
> UnmapOrDieVmar(addr, size, _zx_vmar_root_self());
> }
>
> -// This is used on the shadow mapping, which cannot be changed.
> -// Zircon doesn't have anything like MADV_DONTNEED.
> -void ReleaseMemoryPagesToOS(uptr beg, uptr end) {}
> +void ReleaseMemoryPagesToOS(uptr beg, uptr end) {
> + uptr beg_aligned = RoundUpTo(beg, GetPageSize());
> + uptr end_aligned = RoundDownTo(end, GetPageSize());
> + if (beg_aligned < end_aligned) {
> + zx_handle_t root_vmar = _zx_vmar_root_self();
> + CHECK_NE(root_vmar, ZX_HANDLE_INVALID);
> + zx_status_t status =
> + _zx_vmar_op_range(root_vmar, ZX_VMAR_OP_DECOMMIT, beg_aligned,
> + end_aligned - beg_aligned, nullptr, 0);
> + CHECK_EQ(status, ZX_OK);
> + }
> +}
>
> void DumpProcessMap() {
> // TODO(mcgrathr): write it
> @@ -412,8 +418,9 @@ bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size,
> uint64_t vmo_size;
> status = _zx_vmo_get_size(vmo, &vmo_size);
> if (status == ZX_OK) {
> - if (vmo_size < max_len) max_len = vmo_size;
> - size_t map_size = RoundUpTo(max_len, PAGE_SIZE);
> + if (vmo_size < max_len)
> + max_len = vmo_size;
> + size_t map_size = RoundUpTo(max_len, GetPageSize());
> uintptr_t addr;
> status = _zx_vmar_map(_zx_vmar_root_self(), ZX_VM_PERM_READ, 0, vmo, 0,
> map_size, &addr);
> @@ -425,7 +432,8 @@ bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size,
> }
> _zx_handle_close(vmo);
> }
> - if (status != ZX_OK && errno_p) *errno_p = status;
> + if (status != ZX_OK && errno_p)
> + *errno_p = status;
> return status == ZX_OK;
> }
>
> @@ -499,9 +507,7 @@ bool GetRandom(void *buffer, uptr length, bool blocking) {
> return true;
> }
>
> -u32 GetNumberOfCPUs() {
> - return zx_system_get_num_cpus();
> -}
> +u32 GetNumberOfCPUs() { return zx_system_get_num_cpus(); }
>
> uptr GetRSS() { UNIMPLEMENTED(); }
>
> @@ -529,6 +535,10 @@ void __sanitizer_set_report_path(const char *path) {
> void __sanitizer_set_report_fd(void *fd) {
> UNREACHABLE("not available on Fuchsia");
> }
> +
> +const char *__sanitizer_get_report_path() {
> + UNREACHABLE("not available on Fuchsia");
> +}
> } // extern "C"
>
> #endif // SANITIZER_FUCHSIA
> diff --git a/libsanitizer/sanitizer_common/sanitizer_interface_internal.h b/libsanitizer/sanitizer_common/sanitizer_interface_internal.h
> index be8023e9e16..0b001c1c483 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_interface_internal.h
> +++ b/libsanitizer/sanitizer_common/sanitizer_interface_internal.h
> @@ -28,6 +28,10 @@ extern "C" {
> // (casted to void *).
> SANITIZER_INTERFACE_ATTRIBUTE
> void __sanitizer_set_report_fd(void *fd);
> + // Get the current full report file path, if a path was specified by
> + // an earlier call to __sanitizer_set_report_path. Returns null otherwise.
> + SANITIZER_INTERFACE_ATTRIBUTE
> + const char *__sanitizer_get_report_path();
>
> typedef struct {
> int coverage_sandboxed;
> diff --git a/libsanitizer/sanitizer_common/sanitizer_internal_defs.h b/libsanitizer/sanitizer_common/sanitizer_internal_defs.h
> index d8f0540037d..84053fec264 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_internal_defs.h
> +++ b/libsanitizer/sanitizer_common/sanitizer_internal_defs.h
> @@ -409,6 +409,9 @@ inline void Trap() {
> (void)enable_fp; \
> } while (0)
>
> +constexpr u32 kInvalidTid = -1;
> +constexpr u32 kMainTid = 0;
> +
> } // namespace __sanitizer
>
> namespace __asan {
> diff --git a/libsanitizer/sanitizer_common/sanitizer_libignore.cpp b/libsanitizer/sanitizer_common/sanitizer_libignore.cpp
> index 9ea19bc21fa..a65d3d896e3 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_libignore.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_libignore.cpp
> @@ -38,7 +38,7 @@ void LibIgnore::AddIgnoredLibrary(const char *name_templ) {
> void LibIgnore::OnLibraryLoaded(const char *name) {
> BlockingMutexLock lock(&mutex_);
> // Try to match suppressions with symlink target.
> - InternalScopedString buf(kMaxPathLength);
> + InternalMmapVector<char> buf(kMaxPathLength);
> if (name && internal_readlink(name, buf.data(), buf.size() - 1) > 0 &&
> buf[0]) {
> for (uptr i = 0; i < count_; i++) {
> diff --git a/libsanitizer/sanitizer_common/sanitizer_linux.cpp b/libsanitizer/sanitizer_common/sanitizer_linux.cpp
> index 379f6d9e294..b371477755f 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_linux.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_linux.cpp
> @@ -183,6 +183,14 @@ uptr internal_munmap(void *addr, uptr length) {
> return internal_syscall(SYSCALL(munmap), (uptr)addr, length);
> }
>
> +#if SANITIZER_LINUX
> +uptr internal_mremap(void *old_address, uptr old_size, uptr new_size, int flags,
> + void *new_address) {
> + return internal_syscall(SYSCALL(mremap), (uptr)old_address, old_size,
> + new_size, flags, (uptr)new_address);
> +}
> +#endif
> +
> int internal_mprotect(void *addr, uptr length, int prot) {
> return internal_syscall(SYSCALL(mprotect), (uptr)addr, length, prot);
> }
> @@ -489,22 +497,24 @@ int TgKill(pid_t pid, tid_t tid, int sig) {
> }
> #endif
>
> -#if !SANITIZER_SOLARIS && !SANITIZER_NETBSD
> +#if SANITIZER_GLIBC
> u64 NanoTime() {
> -#if SANITIZER_FREEBSD
> - timeval tv;
> -#else
> kernel_timeval tv;
> -#endif
> internal_memset(&tv, 0, sizeof(tv));
> internal_syscall(SYSCALL(gettimeofday), &tv, 0);
> - return (u64)tv.tv_sec * 1000*1000*1000 + tv.tv_usec * 1000;
> + return (u64)tv.tv_sec * 1000 * 1000 * 1000 + tv.tv_usec * 1000;
> }
> -
> +// Used by real_clock_gettime.
> uptr internal_clock_gettime(__sanitizer_clockid_t clk_id, void *tp) {
> return internal_syscall(SYSCALL(clock_gettime), clk_id, tp);
> }
> -#endif // !SANITIZER_SOLARIS && !SANITIZER_NETBSD
> +#elif !SANITIZER_SOLARIS && !SANITIZER_NETBSD
> +u64 NanoTime() {
> + struct timespec ts;
> + clock_gettime(CLOCK_REALTIME, &ts);
> + return (u64)ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
> +}
> +#endif
>
> // Like getenv, but reads env directly from /proc (on Linux) or parses the
> // 'environ' array (on some others) and does not use libc. This function
> @@ -1334,50 +1344,42 @@ uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
> #elif SANITIZER_RISCV64
> uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
> int *parent_tidptr, void *newtls, int *child_tidptr) {
> - long long res;
> if (!fn || !child_stack)
> return -EINVAL;
> +
> CHECK_EQ(0, (uptr)child_stack % 16);
> - 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 int (*__fn)(void *) __asm__("a0") = fn;
> + register int res __asm__("a0");
> + register int __flags __asm__("a0") = flags;
> register void *__stack __asm__("a1") = child_stack;
> - register int __flags __asm__("a2") = flags;
> - register void *__arg __asm__("a3") = arg;
> - register int *__ptid __asm__("a4") = parent_tidptr;
> - register void *__tls __asm__("a5") = newtls;
> - register int *__ctid __asm__("a6") = child_tidptr;
> + register int *__ptid __asm__("a2") = parent_tidptr;
> + register void *__tls __asm__("a3") = newtls;
> + register int *__ctid __asm__("a4") = child_tidptr;
> + register int (*__fn)(void *) __asm__("a5") = fn;
> + register void *__arg __asm__("a6") = arg;
> + register int nr_clone __asm__("a7") = __NR_clone;
>
> __asm__ __volatile__(
> - "mv a0,a2\n" /* flags */
> - "mv a2,a4\n" /* ptid */
> - "mv a3,a5\n" /* tls */
> - "mv a4,a6\n" /* ctid */
> - "addi a7, zero, %9\n" /* clone */
> -
> "ecall\n"
>
> - /* if (%r0 != 0)
> - * return %r0;
> + /* if (a0 != 0)
> + * return a0;
> */
> "bnez a0, 1f\n"
>
> - /* In the child, now. Call "fn(arg)". */
> - "ld a0, 8(sp)\n"
> - "ld a1, 16(sp)\n"
> - "jalr a1\n"
> + // In the child, now. Call "fn(arg)".
> + "mv a0, a6\n"
> + "jalr a5\n"
>
> - /* Call _exit(%r0). */
> - "addi a7, zero, %10\n"
> + // Call _exit(a0).
> + "addi a7, zero, %9\n"
> "ecall\n"
> "1:\n"
>
> : "=r"(res)
> - : "i"(-EINVAL), "r"(__fn), "r"(__stack), "r"(__flags), "r"(__arg),
> - "r"(__ptid), "r"(__tls), "r"(__ctid), "i"(__NR_clone), "i"(__NR_exit)
> - : "ra", "memory");
> + : "0"(__flags), "r"(__stack), "r"(__ptid), "r"(__tls), "r"(__ctid),
> + "r"(__fn), "r"(__arg), "r"(nr_clone), "i"(__NR_exit)
> + : "memory");
> return res;
> }
> #elif defined(__aarch64__)
> diff --git a/libsanitizer/sanitizer_common/sanitizer_linux.h b/libsanitizer/sanitizer_common/sanitizer_linux.h
> index 24902d1b6bc..9a23fcfb3b9 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_linux.h
> +++ b/libsanitizer/sanitizer_common/sanitizer_linux.h
> @@ -49,7 +49,9 @@ uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count);
> uptr internal_sigaltstack(const void* ss, void* oss);
> uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set,
> __sanitizer_sigset_t *oldset);
> +#if SANITIZER_GLIBC
> uptr internal_clock_gettime(__sanitizer_clockid_t clk_id, void *tp);
> +#endif
>
> // Linux-only syscalls.
> #if SANITIZER_LINUX
> @@ -96,7 +98,6 @@ class ThreadLister {
> // Exposed for testing.
> uptr ThreadDescriptorSize();
> uptr ThreadSelf();
> -uptr ThreadSelfOffset();
>
> // Matches a library's file name against a base name (stripping path and version
> // information).
> diff --git a/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp
> index bc10e89b1ed..572aa86fa53 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp
> @@ -36,6 +36,7 @@
> #include <link.h>
> #include <pthread.h>
> #include <signal.h>
> +#include <sys/mman.h>
> #include <sys/resource.h>
> #include <syslog.h>
>
> @@ -48,6 +49,10 @@
> #include <osreldate.h>
> #include <sys/sysctl.h>
> #define pthread_getattr_np pthread_attr_get_np
> +// The MAP_NORESERVE define has been removed in FreeBSD 11.x, and even before
> +// that, it was never implemented. So just define it to zero.
> +#undef MAP_NORESERVE
> +#define MAP_NORESERVE 0
> #endif
>
> #if SANITIZER_NETBSD
> @@ -183,85 +188,35 @@ __attribute__((unused)) static bool GetLibcVersion(int *major, int *minor,
> #endif
> }
>
> -#if !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_GO && \
> - !SANITIZER_NETBSD && !SANITIZER_SOLARIS
> -static uptr g_tls_size;
> +// True if we can use dlpi_tls_data. glibc before 2.25 may leave NULL (BZ
> +// #19826) so dlpi_tls_data cannot be used.
> +//
> +// musl before 1.2.3 and FreeBSD as of 12.2 incorrectly set dlpi_tls_data to
> +// the TLS initialization image
> +// https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=254774
> +__attribute__((unused)) static int g_use_dlpi_tls_data;
>
> -#ifdef __i386__
> -#define CHECK_GET_TLS_STATIC_INFO_VERSION (!__GLIBC_PREREQ(2, 27))
> -#else
> -#define CHECK_GET_TLS_STATIC_INFO_VERSION 0
> -#endif
> +#if SANITIZER_GLIBC && !SANITIZER_GO
> +__attribute__((unused)) static uptr g_tls_size;
> +void InitTlsSize() {
> + int major, minor, patch;
> + g_use_dlpi_tls_data =
> + GetLibcVersion(&major, &minor, &patch) && major == 2 && minor >= 25;
>
> -#if CHECK_GET_TLS_STATIC_INFO_VERSION
> -#define DL_INTERNAL_FUNCTION __attribute__((regparm(3), stdcall))
> -#else
> -#define DL_INTERNAL_FUNCTION
> +#if defined(__x86_64__) || defined(__powerpc64__)
> + void *get_tls_static_info = dlsym(RTLD_NEXT, "_dl_get_tls_static_info");
> + size_t tls_align;
> + ((void (*)(size_t *, size_t *))get_tls_static_info)(&g_tls_size, &tls_align);
> #endif
> -
> -namespace {
> -struct GetTlsStaticInfoCall {
> - typedef void (*get_tls_func)(size_t*, size_t*);
> -};
> -struct GetTlsStaticInfoRegparmCall {
> - typedef void (*get_tls_func)(size_t*, size_t*) DL_INTERNAL_FUNCTION;
> -};
> -
> -template <typename T>
> -void CallGetTls(void* ptr, size_t* size, size_t* align) {
> - typename T::get_tls_func get_tls;
> - CHECK_EQ(sizeof(get_tls), sizeof(ptr));
> - internal_memcpy(&get_tls, &ptr, sizeof(ptr));
> - CHECK_NE(get_tls, 0);
> - get_tls(size, align);
> -}
> -
> -bool CmpLibcVersion(int major, int minor, int patch) {
> - int ma;
> - int mi;
> - int pa;
> - if (!GetLibcVersion(&ma, &mi, &pa))
> - return false;
> - if (ma > major)
> - return true;
> - if (ma < major)
> - return false;
> - if (mi > minor)
> - return true;
> - if (mi < minor)
> - return false;
> - return pa >= patch;
> -}
> -
> -} // namespace
> -
> -void InitTlsSize() {
> - // all current supported platforms have 16 bytes stack alignment
> - const size_t kStackAlign = 16;
> - void *get_tls_static_info_ptr = dlsym(RTLD_NEXT, "_dl_get_tls_static_info");
> - size_t tls_size = 0;
> - size_t tls_align = 0;
> - // On i?86, _dl_get_tls_static_info used to be internal_function, i.e.
> - // __attribute__((regparm(3), stdcall)) before glibc 2.27 and is normal
> - // function in 2.27 and later.
> - if (CHECK_GET_TLS_STATIC_INFO_VERSION && !CmpLibcVersion(2, 27, 0))
> - CallGetTls<GetTlsStaticInfoRegparmCall>(get_tls_static_info_ptr,
> - &tls_size, &tls_align);
> - else
> - CallGetTls<GetTlsStaticInfoCall>(get_tls_static_info_ptr,
> - &tls_size, &tls_align);
> - if (tls_align < kStackAlign)
> - tls_align = kStackAlign;
> - g_tls_size = RoundUpTo(tls_size, tls_align);
> }
> #else
> void InitTlsSize() { }
> -#endif
> +#endif // SANITIZER_GLIBC && !SANITIZER_GO
>
> -#if (defined(__x86_64__) || defined(__i386__) || defined(__mips__) || \
> - defined(__aarch64__) || defined(__powerpc64__) || defined(__s390__) || \
> - defined(__arm__) || SANITIZER_RISCV64) && \
> - SANITIZER_LINUX && !SANITIZER_ANDROID
> +// On glibc x86_64, ThreadDescriptorSize() needs to be precise due to the usage
> +// of g_tls_size. On other targets, ThreadDescriptorSize() is only used by lsan
> +// to get the pointer to thread-specific data keys in the thread control block.
> +#if (SANITIZER_FREEBSD || SANITIZER_LINUX) && !SANITIZER_ANDROID
> // sizeof(struct pthread) from glibc.
> static atomic_uintptr_t thread_descriptor_size;
>
> @@ -294,9 +249,18 @@ uptr ThreadDescriptorSize() {
> val = FIRST_32_SECOND_64(1168, 2288);
> else if (minor <= 14)
> val = FIRST_32_SECOND_64(1168, 2304);
> - else
> + else if (minor < 32) // Unknown version
> val = FIRST_32_SECOND_64(1216, 2304);
> + else // minor == 32
> + val = FIRST_32_SECOND_64(1344, 2496);
> }
> +#elif defined(__s390__) || defined(__sparc__)
> + // The size of a prefix of TCB including pthread::{specific_1stblock,specific}
> + // suffices. Just return offsetof(struct pthread, specific_used), which hasn't
> + // changed since 2007-05. Technically this applies to i386/x86_64 as well but
> + // we call _dl_get_tls_static_info and need the precise size of struct
> + // pthread.
> + return FIRST_32_SECOND_64(524, 1552);
> #elif defined(__mips__)
> // TODO(sagarthakur): add more values as per different glibc versions.
> val = FIRST_32_SECOND_64(1152, 1776);
> @@ -320,21 +284,12 @@ uptr ThreadDescriptorSize() {
> val = 1776;
> #elif defined(__powerpc64__)
> val = 1776; // from glibc.ppc64le 2.20-8.fc21
> -#elif defined(__s390__)
> - val = FIRST_32_SECOND_64(1152, 1776); // valid for glibc 2.22
> #endif
> if (val)
> atomic_store_relaxed(&thread_descriptor_size, val);
> return val;
> }
>
> -// The offset at which pointer to self is located in the thread descriptor.
> -const uptr kThreadSelfOffset = FIRST_32_SECOND_64(8, 16);
> -
> -uptr ThreadSelfOffset() {
> - return kThreadSelfOffset;
> -}
> -
> #if defined(__mips__) || defined(__powerpc64__) || SANITIZER_RISCV64
> // TlsPreTcbSize includes size of struct pthread_descr and size of tcb
> // head structure. It lies before the static tls blocks.
> @@ -353,68 +308,74 @@ static uptr TlsPreTcbSize() {
> }
> #endif
>
> -uptr ThreadSelf() {
> - uptr descr_addr;
> -#if defined(__i386__)
> - asm("mov %%gs:%c1,%0" : "=r"(descr_addr) : "i"(kThreadSelfOffset));
> -#elif defined(__x86_64__)
> - asm("mov %%fs:%c1,%0" : "=r"(descr_addr) : "i"(kThreadSelfOffset));
> -#elif defined(__mips__)
> - // MIPS uses TLS variant I. The thread pointer (in hardware register $29)
> - // points to the end of the TCB + 0x7000. The pthread_descr structure is
> - // immediately in front of the TCB. TlsPreTcbSize() includes the size of the
> - // TCB and the size of pthread_descr.
> - const uptr kTlsTcbOffset = 0x7000;
> - uptr thread_pointer;
> - asm volatile(".set push;\
> - .set mips64r2;\
> - rdhwr %0,$29;\
> - .set pop" : "=r" (thread_pointer));
> - descr_addr = thread_pointer - kTlsTcbOffset - TlsPreTcbSize();
> -#elif defined(__aarch64__) || defined(__arm__)
> - descr_addr = reinterpret_cast<uptr>(__builtin_thread_pointer()) -
> - ThreadDescriptorSize();
> -#elif SANITIZER_RISCV64
> - // https://github.com/riscv/riscv-elf-psabi-doc/issues/53
> - uptr thread_pointer = reinterpret_cast<uptr>(__builtin_thread_pointer());
> - descr_addr = thread_pointer - TlsPreTcbSize();
> -#elif defined(__s390__)
> - descr_addr = reinterpret_cast<uptr>(__builtin_thread_pointer());
> -#elif defined(__powerpc64__)
> - // PPC64LE uses TLS variant I. The thread pointer (in GPR 13)
> - // points to the end of the TCB + 0x7000. The pthread_descr structure is
> - // immediately in front of the TCB. TlsPreTcbSize() includes the size of the
> - // TCB and the size of pthread_descr.
> - const uptr kTlsTcbOffset = 0x7000;
> - uptr thread_pointer;
> - asm("addi %0,13,%1" : "=r"(thread_pointer) : "I"(-kTlsTcbOffset));
> - descr_addr = thread_pointer - TlsPreTcbSize();
> -#else
> -#error "unsupported CPU arch"
> -#endif
> - return descr_addr;
> -}
> -#endif // (x86_64 || i386 || MIPS) && SANITIZER_LINUX
> +#if !SANITIZER_GO
> +namespace {
> +struct TlsBlock {
> + uptr begin, end, align;
> + size_t tls_modid;
> + bool operator<(const TlsBlock &rhs) const { return begin < rhs.begin; }
> +};
> +} // namespace
>
> -#if SANITIZER_FREEBSD
> -static void **ThreadSelfSegbase() {
> - void **segbase = 0;
> -#if defined(__i386__)
> - // sysarch(I386_GET_GSBASE, segbase);
> - __asm __volatile("mov %%gs:0, %0" : "=r" (segbase));
> -#elif defined(__x86_64__)
> - // sysarch(AMD64_GET_FSBASE, segbase);
> - __asm __volatile("movq %%fs:0, %0" : "=r" (segbase));
> -#else
> -#error "unsupported CPU arch"
> +extern "C" void *__tls_get_addr(size_t *);
> +
> +static int CollectStaticTlsBlocks(struct dl_phdr_info *info, size_t size,
> + void *data) {
> + if (!info->dlpi_tls_modid)
> + return 0;
> + uptr begin = (uptr)info->dlpi_tls_data;
> +#ifndef __s390__
> + if (!g_use_dlpi_tls_data) {
> + // Call __tls_get_addr as a fallback. This forces TLS allocation on glibc
> + // and FreeBSD.
> + size_t mod_and_off[2] = {info->dlpi_tls_modid, 0};
> + begin = (uptr)__tls_get_addr(mod_and_off);
> + }
> #endif
> - return segbase;
> + for (unsigned i = 0; i != info->dlpi_phnum; ++i)
> + if (info->dlpi_phdr[i].p_type == PT_TLS) {
> + static_cast<InternalMmapVector<TlsBlock> *>(data)->push_back(
> + TlsBlock{begin, begin + info->dlpi_phdr[i].p_memsz,
> + info->dlpi_phdr[i].p_align, info->dlpi_tls_modid});
> + break;
> + }
> + return 0;
> }
>
> -uptr ThreadSelf() {
> - return (uptr)ThreadSelfSegbase()[2];
> -}
> -#endif // SANITIZER_FREEBSD
> +__attribute__((unused)) static void GetStaticTlsBoundary(uptr *addr, uptr *size,
> + uptr *align) {
> + InternalMmapVector<TlsBlock> ranges;
> + dl_iterate_phdr(CollectStaticTlsBlocks, &ranges);
> + uptr len = ranges.size();
> + Sort(ranges.begin(), len);
> + // Find the range with tls_modid=1. For glibc, because libc.so uses PT_TLS,
> + // this module is guaranteed to exist and is one of the initially loaded
> + // modules.
> + uptr one = 0;
> + while (one != len && ranges[one].tls_modid != 1) ++one;
> + if (one == len) {
> + // This may happen with musl if no module uses PT_TLS.
> + *addr = 0;
> + *size = 0;
> + *align = 1;
> + return;
> + }
> + // Find the maximum consecutive ranges. We consider two modules consecutive if
> + // the gap is smaller than the alignment. The dynamic loader places static TLS
> + // blocks this way not to waste space.
> + uptr l = one;
> + *align = ranges[l].align;
> + while (l != 0 && ranges[l].begin < ranges[l - 1].end + ranges[l - 1].align)
> + *align = Max(*align, ranges[--l].align);
> + uptr r = one + 1;
> + while (r != len && ranges[r].begin < ranges[r - 1].end + ranges[r - 1].align)
> + *align = Max(*align, ranges[r++].align);
> + *addr = ranges[l].begin;
> + *size = ranges[r - 1].end - ranges[l].begin;
> +}
> +#endif // !SANITIZER_GO
> +#endif // (x86_64 || i386 || mips || ...) && (SANITIZER_FREEBSD ||
> + // SANITIZER_LINUX) && !SANITIZER_ANDROID
>
> #if SANITIZER_NETBSD
> static struct tls_tcb * ThreadSelfTlsTcb() {
> @@ -465,33 +426,67 @@ static void GetTls(uptr *addr, uptr *size) {
> *addr = 0;
> *size = 0;
> }
> -#elif SANITIZER_LINUX
> -#if defined(__x86_64__) || defined(__i386__) || defined(__s390__)
> - *addr = ThreadSelf();
> - *size = GetTlsSize();
> +#elif SANITIZER_GLIBC && defined(__x86_64__)
> + // For x86-64, use an O(1) approach which requires precise
> + // ThreadDescriptorSize. g_tls_size was initialized in InitTlsSize.
> + asm("mov %%fs:16,%0" : "=r"(*addr));
> + *size = g_tls_size;
> *addr -= *size;
> *addr += ThreadDescriptorSize();
> -#elif defined(__mips__) || defined(__aarch64__) || defined(__powerpc64__) || \
> - defined(__arm__) || SANITIZER_RISCV64
> - *addr = ThreadSelf();
> - *size = GetTlsSize();
> +#elif SANITIZER_GLIBC && defined(__powerpc64__)
> + // Workaround for glibc<2.25(?). 2.27 is known to not need this.
> + uptr tp;
> + asm("addi %0,13,-0x7000" : "=r"(tp));
> + const uptr pre_tcb_size = TlsPreTcbSize();
> + *addr = tp - pre_tcb_size;
> + *size = g_tls_size + pre_tcb_size;
> +#elif SANITIZER_FREEBSD || SANITIZER_LINUX
> + uptr align;
> + GetStaticTlsBoundary(addr, size, &align);
> +#if defined(__x86_64__) || defined(__i386__) || defined(__s390__) || \
> + defined(__sparc__)
> + if (SANITIZER_GLIBC) {
> +#if defined(__x86_64__) || defined(__i386__)
> + align = Max<uptr>(align, 64);
> #else
> - *addr = 0;
> - *size = 0;
> + align = Max<uptr>(align, 16);
> #endif
> -#elif SANITIZER_FREEBSD
> - void** segbase = ThreadSelfSegbase();
> - *addr = 0;
> - *size = 0;
> - if (segbase != 0) {
> - // tcbalign = 16
> - // tls_size = round(tls_static_space, tcbalign);
> - // dtv = segbase[1];
> - // dtv[2] = segbase - tls_static_space;
> - void **dtv = (void**) segbase[1];
> - *addr = (uptr) dtv[2];
> - *size = (*addr == 0) ? 0 : ((uptr) segbase[0] - (uptr) dtv[2]);
> }
> + const uptr tp = RoundUpTo(*addr + *size, align);
> +
> + // lsan requires the range to additionally cover the static TLS surplus
> + // (elf/dl-tls.c defines 1664). Otherwise there may be false positives for
> + // allocations only referenced by tls in dynamically loaded modules.
> + if (SANITIZER_GLIBC)
> + *size += 1644;
> + else if (SANITIZER_FREEBSD)
> + *size += 128; // RTLD_STATIC_TLS_EXTRA
> +
> + // Extend the range to include the thread control block. On glibc, lsan needs
> + // the range to include pthread::{specific_1stblock,specific} so that
> + // allocations only referenced by pthread_setspecific can be scanned. This may
> + // underestimate by at most TLS_TCB_ALIGN-1 bytes but it should be fine
> + // because the number of bytes after pthread::specific is larger.
> + *addr = tp - RoundUpTo(*size, align);
> + *size = tp - *addr + ThreadDescriptorSize();
> +#else
> + if (SANITIZER_GLIBC)
> + *size += 1664;
> + else if (SANITIZER_FREEBSD)
> + *size += 128; // RTLD_STATIC_TLS_EXTRA
> +#if defined(__mips__) || defined(__powerpc64__) || SANITIZER_RISCV64
> + const uptr pre_tcb_size = TlsPreTcbSize();
> + *addr -= pre_tcb_size;
> + *size += pre_tcb_size;
> +#else
> + // arm and aarch64 reserve two words at TP, so this underestimates the range.
> + // However, this is sufficient for the purpose of finding the pointers to
> + // thread-specific data keys.
> + const uptr tcb_size = ThreadDescriptorSize();
> + *addr -= tcb_size;
> + *size += tcb_size;
> +#endif
> +#endif
> #elif SANITIZER_NETBSD
> struct tls_tcb * const tcb = ThreadSelfTlsTcb();
> *addr = 0;
> @@ -518,15 +513,13 @@ static void GetTls(uptr *addr, uptr *size) {
>
> #if !SANITIZER_GO
> uptr GetTlsSize() {
> -#if SANITIZER_FREEBSD || SANITIZER_ANDROID || SANITIZER_NETBSD || \
> +#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \
> SANITIZER_SOLARIS
> uptr addr, size;
> GetTls(&addr, &size);
> return size;
> -#elif defined(__mips__) || defined(__powerpc64__) || SANITIZER_RISCV64
> - return RoundUpTo(g_tls_size + TlsPreTcbSize(), 16);
> #else
> - return g_tls_size;
> + return 0;
> #endif
> }
> #endif
> @@ -547,10 +540,9 @@ void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
> if (!main) {
> // If stack and tls intersect, make them non-intersecting.
> if (*tls_addr > *stk_addr && *tls_addr < *stk_addr + *stk_size) {
> - CHECK_GT(*tls_addr + *tls_size, *stk_addr);
> - CHECK_LE(*tls_addr + *tls_size, *stk_addr + *stk_size);
> - *stk_size -= *tls_size;
> - *tls_addr = *stk_addr + *stk_size;
> + if (*stk_addr + *stk_size < *tls_addr + *tls_size)
> + *tls_size = *stk_addr + *stk_size - *tls_addr;
> + *stk_size = *tls_addr - *stk_addr;
> }
> }
> #endif
> @@ -569,20 +561,12 @@ struct DlIteratePhdrData {
> bool first;
> };
>
> -static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) {
> - DlIteratePhdrData *data = (DlIteratePhdrData*)arg;
> - InternalScopedString module_name(kMaxPathLength);
> - if (data->first) {
> - data->first = false;
> - // First module is the binary itself.
> - ReadBinaryNameCached(module_name.data(), module_name.size());
> - } else if (info->dlpi_name) {
> - module_name.append("%s", info->dlpi_name);
> - }
> +static int AddModuleSegments(const char *module_name, dl_phdr_info *info,
> + InternalMmapVectorNoCtor<LoadedModule> *modules) {
> if (module_name[0] == '\0')
> return 0;
> LoadedModule cur_module;
> - cur_module.set(module_name.data(), info->dlpi_addr);
> + cur_module.set(module_name, info->dlpi_addr);
> for (int i = 0; i < (int)info->dlpi_phnum; i++) {
> const Elf_Phdr *phdr = &info->dlpi_phdr[i];
> if (phdr->p_type == PT_LOAD) {
> @@ -594,7 +578,26 @@ static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) {
> writable);
> }
> }
> - data->modules->push_back(cur_module);
> + modules->push_back(cur_module);
> + return 0;
> +}
> +
> +static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) {
> + DlIteratePhdrData *data = (DlIteratePhdrData *)arg;
> + if (data->first) {
> + InternalMmapVector<char> module_name(kMaxPathLength);
> + data->first = false;
> + // First module is the binary itself.
> + ReadBinaryNameCached(module_name.data(), module_name.size());
> + return AddModuleSegments(module_name.data(), info, data->modules);
> + }
> +
> + if (info->dlpi_name) {
> + InternalScopedString module_name;
> + module_name.append("%s", info->dlpi_name);
> + return AddModuleSegments(module_name.data(), info, data->modules);
> + }
> +
> return 0;
> }
>
> @@ -729,13 +732,9 @@ u32 GetNumberOfCPUs() {
> #elif SANITIZER_SOLARIS
> return sysconf(_SC_NPROCESSORS_ONLN);
> #else
> -#if defined(CPU_COUNT)
> cpu_set_t CPUs;
> CHECK_EQ(sched_getaffinity(0, sizeof(cpu_set_t), &CPUs), 0);
> return CPU_COUNT(&CPUs);
> -#else
> - return 1;
> -#endif
> #endif
> }
>
> @@ -802,20 +801,13 @@ void LogMessageOnPrintf(const char *str) {
>
> #endif // SANITIZER_LINUX
>
> -#if SANITIZER_LINUX && !SANITIZER_GO
> +#if SANITIZER_GLIBC && !SANITIZER_GO
> // glibc crashes when using clock_gettime from a preinit_array function as the
> // vDSO function pointers haven't been initialized yet. __progname is
> // initialized after the vDSO function pointers, so if it exists, is not null
> // and is not empty, we can use clock_gettime.
> extern "C" SANITIZER_WEAK_ATTRIBUTE char *__progname;
> -inline bool CanUseVDSO() {
> - // Bionic is safe, it checks for the vDSO function pointers to be initialized.
> - if (SANITIZER_ANDROID)
> - return true;
> - if (&__progname && __progname && *__progname)
> - return true;
> - return false;
> -}
> +inline bool CanUseVDSO() { return &__progname && __progname && *__progname; }
>
> // MonotonicNanoTime is a timing function that can leverage the vDSO by calling
> // clock_gettime. real_clock_gettime only exists if clock_gettime is
> @@ -835,13 +827,13 @@ u64 MonotonicNanoTime() {
> return (u64)ts.tv_sec * (1000ULL * 1000 * 1000) + ts.tv_nsec;
> }
> #else
> -// Non-Linux & Go always use the syscall.
> +// Non-glibc & Go always use the regular function.
> u64 MonotonicNanoTime() {
> timespec ts;
> - internal_clock_gettime(CLOCK_MONOTONIC, &ts);
> + clock_gettime(CLOCK_MONOTONIC, &ts);
> return (u64)ts.tv_sec * (1000ULL * 1000 * 1000) + ts.tv_nsec;
> }
> -#endif // SANITIZER_LINUX && !SANITIZER_GO
> +#endif // SANITIZER_GLIBC && !SANITIZER_GO
>
> void ReExec() {
> const char *pathname = "/proc/self/exe";
> @@ -910,6 +902,65 @@ uptr MapDynamicShadow(uptr shadow_size_bytes, uptr shadow_scale,
> return shadow_start;
> }
>
> +static uptr MmapSharedNoReserve(uptr addr, uptr size) {
> + return internal_mmap(
> + reinterpret_cast<void *>(addr), size, PROT_READ | PROT_WRITE,
> + MAP_FIXED | MAP_SHARED | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
> +}
> +
> +static uptr MremapCreateAlias(uptr base_addr, uptr alias_addr,
> + uptr alias_size) {
> +#if SANITIZER_LINUX
> + return internal_mremap(reinterpret_cast<void *>(base_addr), 0, alias_size,
> + MREMAP_MAYMOVE | MREMAP_FIXED,
> + reinterpret_cast<void *>(alias_addr));
> +#else
> + CHECK(false && "mremap is not supported outside of Linux");
> + return 0;
> +#endif
> +}
> +
> +static void CreateAliases(uptr start_addr, uptr alias_size, uptr num_aliases) {
> + uptr total_size = alias_size * num_aliases;
> + uptr mapped = MmapSharedNoReserve(start_addr, total_size);
> + CHECK_EQ(mapped, start_addr);
> +
> + for (uptr i = 1; i < num_aliases; ++i) {
> + uptr alias_addr = start_addr + i * alias_size;
> + CHECK_EQ(MremapCreateAlias(start_addr, alias_addr, alias_size), alias_addr);
> + }
> +}
> +
> +uptr MapDynamicShadowAndAliases(uptr shadow_size, uptr alias_size,
> + uptr num_aliases, uptr ring_buffer_size) {
> + CHECK_EQ(alias_size & (alias_size - 1), 0);
> + CHECK_EQ(num_aliases & (num_aliases - 1), 0);
> + CHECK_EQ(ring_buffer_size & (ring_buffer_size - 1), 0);
> +
> + const uptr granularity = GetMmapGranularity();
> + shadow_size = RoundUpTo(shadow_size, granularity);
> + CHECK_EQ(shadow_size & (shadow_size - 1), 0);
> +
> + const uptr alias_region_size = alias_size * num_aliases;
> + const uptr alignment =
> + 2 * Max(Max(shadow_size, alias_region_size), ring_buffer_size);
> + const uptr left_padding = ring_buffer_size;
> +
> + const uptr right_size = alignment;
> + const uptr map_size = left_padding + 2 * alignment;
> +
> + const uptr map_start = reinterpret_cast<uptr>(MmapNoAccess(map_size));
> + CHECK_NE(map_start, static_cast<uptr>(-1));
> + const uptr right_start = RoundUpTo(map_start + left_padding, alignment);
> +
> + UnmapFromTo(map_start, right_start - left_padding);
> + UnmapFromTo(right_start + right_size, map_start + map_size);
> +
> + CreateAliases(right_start + right_size / 2, alias_size, num_aliases);
> +
> + return right_start;
> +}
> +
> void InitializePlatformCommonFlags(CommonFlags *cf) {
> #if SANITIZER_ANDROID
> if (&__libc_get_static_tls_bounds == nullptr)
> diff --git a/libsanitizer/sanitizer_common/sanitizer_local_address_space_view.h b/libsanitizer/sanitizer_common/sanitizer_local_address_space_view.h
> index 5d1b5264b5e..0e19c4d4a80 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_local_address_space_view.h
> +++ b/libsanitizer/sanitizer_common/sanitizer_local_address_space_view.h
> @@ -7,7 +7,7 @@
> //===----------------------------------------------------------------------===//
> //
> // `LocalAddressSpaceView` provides the local (i.e. target and current address
> -// space are the same) implementation of the `AddressSpaveView` interface which
> +// space are the same) implementation of the `AddressSpaceView` interface which
> // provides a simple interface to load memory from another process (i.e.
> // out-of-process)
> //
> diff --git a/libsanitizer/sanitizer_common/sanitizer_mac.cpp b/libsanitizer/sanitizer_common/sanitizer_mac.cpp
> index 011ec6f4a0b..f4c6b442a14 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_mac.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_mac.cpp
> @@ -37,13 +37,21 @@
> extern char **environ;
> #endif
>
> -#if defined(__has_include) && __has_include(<os/trace.h>) && defined(__BLOCKS__)
> +#if defined(__has_include) && __has_include(<os/trace.h>)
> #define SANITIZER_OS_TRACE 1
> #include <os/trace.h>
> #else
> #define SANITIZER_OS_TRACE 0
> #endif
>
> +// import new crash reporting api
> +#if defined(__has_include) && __has_include(<CrashReporterClient.h>)
> +#define HAVE_CRASHREPORTERCLIENT_H 1
> +#include <CrashReporterClient.h>
> +#else
> +#define HAVE_CRASHREPORTERCLIENT_H 0
> +#endif
> +
> #if !SANITIZER_IOS
> #include <crt_externs.h> // for _NSGetArgv and _NSGetEnviron
> #else
> @@ -62,6 +70,7 @@ extern "C" {
> #include <mach/mach_time.h>
> #include <mach/vm_statistics.h>
> #include <malloc/malloc.h>
> +#include <os/log.h>
> #include <pthread.h>
> #include <sched.h>
> #include <signal.h>
> @@ -133,6 +142,12 @@ uptr internal_munmap(void *addr, uptr length) {
> return munmap(addr, length);
> }
>
> +uptr internal_mremap(void *old_address, uptr old_size, uptr new_size, int flags,
> + void *new_address) {
> + CHECK(false && "internal_mremap is unimplemented on Mac");
> + return 0;
> +}
> +
> int internal_mprotect(void *addr, uptr length, int prot) {
> return mprotect(addr, length, prot);
> }
> @@ -444,7 +459,7 @@ uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {
> // On OS X the executable path is saved to the stack by dyld. Reading it
> // from there is much faster than calling dladdr, especially for large
> // binaries with symbols.
> - InternalScopedString exe_path(kMaxPathLength);
> + InternalMmapVector<char> exe_path(kMaxPathLength);
> uint32_t size = exe_path.size();
> if (_NSGetExecutablePath(exe_path.data(), &size) == 0 &&
> realpath(exe_path.data(), buf) != 0) {
> @@ -620,6 +635,23 @@ constexpr u16 GetOSMajorKernelOffset() {
>
> using VersStr = char[64];
>
> +static uptr ApproximateOSVersionViaKernelVersion(VersStr vers) {
> + u16 kernel_major = GetDarwinKernelVersion().major;
> + u16 offset = GetOSMajorKernelOffset();
> + CHECK_GE(kernel_major, offset);
> + u16 os_major = kernel_major - offset;
> +
> + const char *format = "%d.0";
> + if (TARGET_OS_OSX) {
> + if (os_major >= 16) { // macOS 11+
> + os_major -= 5;
> + } else { // macOS 10.15 and below
> + format = "10.%d";
> + }
> + }
> + return internal_snprintf(vers, sizeof(VersStr), format, os_major);
> +}
> +
> static void GetOSVersion(VersStr vers) {
> uptr len = sizeof(VersStr);
> if (SANITIZER_IOSSIM) {
> @@ -633,17 +665,19 @@ static void GetOSVersion(VersStr vers) {
> } else {
> int res =
> internal_sysctlbyname("kern.osproductversion", vers, &len, nullptr, 0);
> - if (res) {
> - // Fallback for XNU 17 (macOS 10.13) and below that do not provide the
> - // `kern.osproductversion` property.
> - u16 kernel_major = GetDarwinKernelVersion().major;
> - u16 offset = GetOSMajorKernelOffset();
> - CHECK_LE(kernel_major, 17);
> - CHECK_GE(kernel_major, offset);
> - u16 os_major = kernel_major - offset;
> -
> - auto format = TARGET_OS_OSX ? "10.%d" : "%d.0";
> - len = internal_snprintf(vers, len, format, os_major);
> +
> + // XNU 17 (macOS 10.13) and below do not provide the sysctl
> + // `kern.osproductversion` entry (res != 0).
> + bool no_os_version = res != 0;
> +
> + // For launchd, sanitizer initialization runs before sysctl is setup
> + // (res == 0 && len != strlen(vers), vers is not a valid version). However,
> + // the kernel version `kern.osrelease` is available.
> + bool launchd = (res == 0 && internal_strlen(vers) < 3);
> + if (launchd) CHECK_EQ(internal_getpid(), 1);
> +
> + if (no_os_version || launchd) {
> + len = ApproximateOSVersionViaKernelVersion(vers);
> }
> }
> CHECK_LT(len, sizeof(VersStr));
> @@ -681,7 +715,7 @@ static void MapToMacos(u16 *major, u16 *minor) {
> }
>
> static MacosVersion GetMacosAlignedVersionInternal() {
> - VersStr vers;
> + VersStr vers = {};
> GetOSVersion(vers);
>
> u16 major, minor;
> @@ -707,7 +741,7 @@ MacosVersion GetMacosAlignedVersion() {
> }
>
> DarwinKernelVersion GetDarwinKernelVersion() {
> - VersStr vers;
> + VersStr vers = {};
> uptr len = sizeof(VersStr);
> int res = internal_sysctlbyname("kern.osrelease", vers, &len, nullptr, 0);
> CHECK_EQ(res, 0);
> @@ -751,7 +785,51 @@ static BlockingMutex syslog_lock(LINKER_INITIALIZED);
> void WriteOneLineToSyslog(const char *s) {
> #if !SANITIZER_GO
> syslog_lock.CheckLocked();
> - asl_log(nullptr, nullptr, ASL_LEVEL_ERR, "%s", s);
> + if (GetMacosAlignedVersion() >= MacosVersion(10, 12)) {
> + os_log_error(OS_LOG_DEFAULT, "%{public}s", s);
> + } else {
> + asl_log(nullptr, nullptr, ASL_LEVEL_ERR, "%s", s);
> + }
> +#endif
> +}
> +
> +// buffer to store crash report application information
> +static char crashreporter_info_buff[__sanitizer::kErrorMessageBufferSize] = {};
> +static BlockingMutex crashreporter_info_mutex(LINKER_INITIALIZED);
> +
> +extern "C" {
> +// Integrate with crash reporter libraries.
> +#if HAVE_CRASHREPORTERCLIENT_H
> +CRASH_REPORTER_CLIENT_HIDDEN
> +struct crashreporter_annotations_t gCRAnnotations
> + __attribute__((section("__DATA," CRASHREPORTER_ANNOTATIONS_SECTION))) = {
> + CRASHREPORTER_ANNOTATIONS_VERSION,
> + 0,
> + 0,
> + 0,
> + 0,
> + 0,
> + 0,
> +#if CRASHREPORTER_ANNOTATIONS_VERSION > 4
> + 0,
> +#endif
> +};
> +
> +#else
> +// fall back to old crashreporter api
> +static const char *__crashreporter_info__ __attribute__((__used__)) =
> + &crashreporter_info_buff[0];
> +asm(".desc ___crashreporter_info__, 0x10");
> +#endif
> +
> +} // extern "C"
> +
> +static void CRAppendCrashLogMessage(const char *msg) {
> + BlockingMutexLock l(&crashreporter_info_mutex);
> + internal_strlcat(crashreporter_info_buff, msg,
> + sizeof(crashreporter_info_buff));
> +#if HAVE_CRASHREPORTERCLIENT_H
> + (void)CRSetCrashLogMessage(crashreporter_info_buff);
> #endif
> }
>
> @@ -947,7 +1025,7 @@ void MaybeReexec() {
> if (DyldNeedsEnvVariable() && !lib_is_in_env) {
> // DYLD_INSERT_LIBRARIES is not set or does not contain the runtime
> // library.
> - InternalScopedString program_name(1024);
> + InternalMmapVector<char> program_name(1024);
> uint32_t buf_size = program_name.size();
> _NSGetExecutablePath(program_name.data(), &buf_size);
> char *new_env = const_cast<char*>(info.dli_fname);
> @@ -1066,7 +1144,7 @@ char **GetArgv() {
> return *_NSGetArgv();
> }
>
> -#if SANITIZER_IOS
> +#if SANITIZER_IOS && !SANITIZER_IOSSIM
> // The task_vm_info struct is normally provided by the macOS SDK, but we need
> // fields only available in 10.12+. Declare the struct manually to be able to
> // build against older SDKs.
> @@ -1106,26 +1184,35 @@ static uptr GetTaskInfoMaxAddress() {
>
> uptr GetMaxUserVirtualAddress() {
> static uptr max_vm = GetTaskInfoMaxAddress();
> - if (max_vm != 0)
> - return max_vm - 1;
> + if (max_vm != 0) {
> + const uptr ret_value = max_vm - 1;
> + CHECK_LE(ret_value, SANITIZER_MMAP_RANGE_SIZE);
> + return ret_value;
> + }
>
> // xnu cannot provide vm address limit
> # if SANITIZER_WORDSIZE == 32
> - return 0xffe00000 - 1;
> + constexpr uptr fallback_max_vm = 0xffe00000 - 1;
> # else
> - return 0x200000000 - 1;
> + constexpr uptr fallback_max_vm = 0x200000000 - 1;
> # endif
> + static_assert(fallback_max_vm <= SANITIZER_MMAP_RANGE_SIZE,
> + "Max virtual address must be less than mmap range size.");
> + return fallback_max_vm;
> }
>
> #else // !SANITIZER_IOS
>
> uptr GetMaxUserVirtualAddress() {
> # if SANITIZER_WORDSIZE == 64
> - return (1ULL << 47) - 1; // 0x00007fffffffffffUL;
> + constexpr uptr max_vm = (1ULL << 47) - 1; // 0x00007fffffffffffUL;
> # else // SANITIZER_WORDSIZE == 32
> static_assert(SANITIZER_WORDSIZE == 32, "Wrong wordsize");
> - return (1ULL << 32) - 1; // 0xffffffff;
> + constexpr uptr max_vm = (1ULL << 32) - 1; // 0xffffffff;
> # endif
> + static_assert(max_vm <= SANITIZER_MMAP_RANGE_SIZE,
> + "Max virtual address must be less than mmap range size.");
> + return max_vm;
> }
> #endif
>
> @@ -1180,6 +1267,12 @@ uptr MapDynamicShadow(uptr shadow_size_bytes, uptr shadow_scale,
> return shadow_start;
> }
>
> +uptr MapDynamicShadowAndAliases(uptr shadow_size, uptr alias_size,
> + uptr num_aliases, uptr ring_buffer_size) {
> + CHECK(false && "HWASan aliasing is unimplemented on Mac");
> + return 0;
> +}
> +
> uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding,
> uptr *largest_gap_found,
> uptr *max_occupied_addr) {
> diff --git a/libsanitizer/sanitizer_common/sanitizer_mac.h b/libsanitizer/sanitizer_common/sanitizer_mac.h
> index a2c42b3bf4f..0b6af5a3c0e 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_mac.h
> +++ b/libsanitizer/sanitizer_common/sanitizer_mac.h
> @@ -14,26 +14,6 @@
>
> #include "sanitizer_common.h"
> #include "sanitizer_platform.h"
> -
> -/* TARGET_OS_OSX is not present in SDKs before Darwin16 (macOS 10.12) use
> - TARGET_OS_MAC (we have no support for iOS in any form for these versions,
> - so there's no ambiguity). */
> -#if !defined(TARGET_OS_OSX) && TARGET_OS_MAC
> -# define TARGET_OS_OSX 1
> -#endif
> -
> -/* Other TARGET_OS_xxx are not present on earlier versions, define them to
> - 0 (we have no support for them; they are not valid targets anyway). */
> -#ifndef TARGET_OS_IOS
> -#define TARGET_OS_IOS 0
> -#endif
> -#ifndef TARGET_OS_TV
> -#define TARGET_OS_TV 0
> -#endif
> -#ifndef TARGET_OS_WATCH
> -#define TARGET_OS_WATCH 0
> -#endif
> -
> #if SANITIZER_MAC
> #include "sanitizer_posix.h"
>
> @@ -84,22 +64,5 @@ void RestrictMemoryToMaxAddress(uptr max_address);
>
> } // namespace __sanitizer
>
> -extern "C" {
> -static char __crashreporter_info_buff__[__sanitizer::kErrorMessageBufferSize] =
> - {};
> -static const char *__crashreporter_info__ __attribute__((__used__)) =
> - &__crashreporter_info_buff__[0];
> -asm(".desc ___crashreporter_info__, 0x10");
> -} // extern "C"
> -
> -namespace __sanitizer {
> -static BlockingMutex crashreporter_info_mutex(LINKER_INITIALIZED);
> -
> -inline void CRAppendCrashLogMessage(const char *msg) {
> - BlockingMutexLock l(&crashreporter_info_mutex);
> - internal_strlcat(__crashreporter_info_buff__, msg,
> - sizeof(__crashreporter_info_buff__)); }
> -} // namespace __sanitizer
> -
> #endif // SANITIZER_MAC
> #endif // SANITIZER_MAC_H
> diff --git a/libsanitizer/sanitizer_common/sanitizer_malloc_mac.inc b/libsanitizer/sanitizer_common/sanitizer_malloc_mac.inc
> index 647bcdfe105..e3b664f68b6 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_malloc_mac.inc
> +++ b/libsanitizer/sanitizer_common/sanitizer_malloc_mac.inc
> @@ -120,11 +120,7 @@ INTERCEPTOR(int, malloc_make_nonpurgeable, void *ptr) {
>
> INTERCEPTOR(void, malloc_set_zone_name, malloc_zone_t *zone, const char *name) {
> COMMON_MALLOC_ENTER();
> - // Allocate |sizeof(COMMON_MALLOC_ZONE_NAME "-") + internal_strlen(name)|
> - // bytes.
> - size_t buflen =
> - sizeof(COMMON_MALLOC_ZONE_NAME "-") + (name ? internal_strlen(name) : 0);
> - InternalScopedString new_name(buflen);
> + InternalScopedString new_name;
> if (name && zone->introspect == sanitizer_zone.introspect) {
> new_name.append(COMMON_MALLOC_ZONE_NAME "-%s", name);
> name = new_name.data();
> diff --git a/libsanitizer/sanitizer_common/sanitizer_netbsd.cpp b/libsanitizer/sanitizer_common/sanitizer_netbsd.cpp
> index 98ac7365da0..ac20f915fef 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_netbsd.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_netbsd.cpp
> @@ -105,6 +105,12 @@ uptr internal_munmap(void *addr, uptr length) {
> return _REAL(munmap, addr, length);
> }
>
> +uptr internal_mremap(void *old_address, uptr old_size, uptr new_size, int flags,
> + void *new_address) {
> + CHECK(false && "internal_mremap is unimplemented on NetBSD");
> + return 0;
> +}
> +
> int internal_mprotect(void *addr, uptr length, int prot) {
> DEFINE__REAL(int, mprotect, void *a, uptr b, int c);
> return _REAL(mprotect, addr, length, prot);
> diff --git a/libsanitizer/sanitizer_common/sanitizer_platform.h b/libsanitizer/sanitizer_common/sanitizer_platform.h
> index b2372a025c0..2f6458431c8 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_platform.h
> +++ b/libsanitizer/sanitizer_common/sanitizer_platform.h
> @@ -19,12 +19,25 @@
> # error "This operating system is not supported"
> #endif
>
> +// Get __GLIBC__ on a glibc platform. Exclude Android: features.h includes C
> +// function declarations into a .S file which doesn't compile.
> +// https://crbug.com/1162741
> +#if __has_include(<features.h>) && !defined(__ANDROID__)
> +#include <features.h>
> +#endif
> +
> #if defined(__linux__)
> # define SANITIZER_LINUX 1
> #else
> # define SANITIZER_LINUX 0
> #endif
>
> +#if defined(__GLIBC__)
> +# define SANITIZER_GLIBC 1
> +#else
> +# define SANITIZER_GLIBC 0
> +#endif
> +
> #if defined(__FreeBSD__)
> # define SANITIZER_FREEBSD 1
> #else
> @@ -46,6 +59,11 @@
> #if defined(__APPLE__)
> # define SANITIZER_MAC 1
> # include <TargetConditionals.h>
> +# if TARGET_OS_OSX
> +# define SANITIZER_OSX 1
> +# else
> +# define SANITIZER_OSX 0
> +# endif
> # if TARGET_OS_IPHONE
> # define SANITIZER_IOS 1
> # else
> @@ -60,6 +78,7 @@
> # define SANITIZER_MAC 0
> # define SANITIZER_IOS 0
> # define SANITIZER_IOSSIM 0
> +# define SANITIZER_OSX 0
> #endif
>
> #if defined(__APPLE__) && TARGET_OS_IPHONE && TARGET_OS_WATCH
> @@ -247,8 +266,12 @@
> #define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 38)
> #elif defined(__aarch64__)
> # if SANITIZER_MAC
> -// Darwin iOS/ARM64 has a 36-bit VMA, 64GiB VM
> -# define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 36)
> +# if SANITIZER_OSX || SANITIZER_IOSSIM
> +# define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 47)
> +# else
> + // Darwin iOS/ARM64 has a 36-bit VMA, 64GiB VM
> +# define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 36)
> +# endif
> # else
> # define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 48)
> # endif
> diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h b/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h
> index 18bab346ce6..731df710df5 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h
> +++ b/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h
> @@ -46,6 +46,12 @@
> #define SI_LINUX_NOT_ANDROID 0
> #endif
>
> +#if SANITIZER_GLIBC
> +#define SI_GLIBC 1
> +#else
> +#define SI_GLIBC 0
> +#endif
> +
> #if SANITIZER_ANDROID
> #define SI_ANDROID 1
> #else
> @@ -159,7 +165,7 @@
> SANITIZER_INTERCEPT_MEMCMP && \
> ((SI_POSIX && _GNU_SOURCE) || SI_NETBSD || SI_FREEBSD)
> #define SANITIZER_INTERCEPT_STRNDUP SI_POSIX
> -#define SANITIZER_INTERCEPT___STRNDUP SI_LINUX_NOT_FREEBSD
> +#define SANITIZER_INTERCEPT___STRNDUP SI_GLIBC
> #if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \
> __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070
> #define SI_MAC_DEPLOYMENT_BELOW_10_7 1
> @@ -183,8 +189,8 @@
> #define SANITIZER_INTERCEPT_FPUTS SI_POSIX
> #define SANITIZER_INTERCEPT_PUTS SI_POSIX
>
> -#define SANITIZER_INTERCEPT_PREAD64 SI_LINUX_NOT_ANDROID || SI_SOLARIS32
> -#define SANITIZER_INTERCEPT_PWRITE64 SI_LINUX_NOT_ANDROID || SI_SOLARIS32
> +#define SANITIZER_INTERCEPT_PREAD64 (SI_GLIBC || SI_SOLARIS32)
> +#define SANITIZER_INTERCEPT_PWRITE64 (SI_GLIBC || SI_SOLARIS32)
>
> #define SANITIZER_INTERCEPT_READV SI_POSIX
> #define SANITIZER_INTERCEPT_WRITEV SI_POSIX
> @@ -192,8 +198,8 @@
> #define SANITIZER_INTERCEPT_PREADV \
> (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID)
> #define SANITIZER_INTERCEPT_PWRITEV SI_LINUX_NOT_ANDROID
> -#define SANITIZER_INTERCEPT_PREADV64 SI_LINUX_NOT_ANDROID
> -#define SANITIZER_INTERCEPT_PWRITEV64 SI_LINUX_NOT_ANDROID
> +#define SANITIZER_INTERCEPT_PREADV64 SI_GLIBC
> +#define SANITIZER_INTERCEPT_PWRITEV64 SI_GLIBC
>
> #define SANITIZER_INTERCEPT_PRCTL SI_LINUX
>
> @@ -201,16 +207,16 @@
> #define SANITIZER_INTERCEPT_STRPTIME SI_POSIX
>
> #define SANITIZER_INTERCEPT_SCANF SI_POSIX
> -#define SANITIZER_INTERCEPT_ISOC99_SCANF SI_LINUX_NOT_ANDROID
> +#define SANITIZER_INTERCEPT_ISOC99_SCANF SI_GLIBC
>
> #ifndef SANITIZER_INTERCEPT_PRINTF
> #define SANITIZER_INTERCEPT_PRINTF SI_POSIX
> #define SANITIZER_INTERCEPT_PRINTF_L (SI_FREEBSD || SI_NETBSD)
> -#define SANITIZER_INTERCEPT_ISOC99_PRINTF SI_LINUX_NOT_ANDROID
> +#define SANITIZER_INTERCEPT_ISOC99_PRINTF SI_GLIBC
> #endif
>
> #define SANITIZER_INTERCEPT___PRINTF_CHK \
> - (SANITIZER_INTERCEPT_PRINTF && SI_LINUX_NOT_ANDROID)
> + (SANITIZER_INTERCEPT_PRINTF && SI_GLIBC)
>
> #define SANITIZER_INTERCEPT_FREXP SI_NOT_FUCHSIA
> #define SANITIZER_INTERCEPT_FREXPF_FREXPL SI_POSIX
> @@ -220,13 +226,11 @@
> (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
> #define SANITIZER_INTERCEPT_GETPWENT \
> (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
> -#define SANITIZER_INTERCEPT_FGETGRENT_R \
> - (SI_FREEBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
> +#define SANITIZER_INTERCEPT_FGETGRENT_R (SI_GLIBC || SI_SOLARIS)
> #define SANITIZER_INTERCEPT_FGETPWENT SI_LINUX_NOT_ANDROID || SI_SOLARIS
> #define SANITIZER_INTERCEPT_GETPWENT_R \
> - (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
> -#define SANITIZER_INTERCEPT_FGETPWENT_R \
> - (SI_FREEBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
> + (SI_FREEBSD || SI_NETBSD || SI_GLIBC || SI_SOLARIS)
> +#define SANITIZER_INTERCEPT_FGETPWENT_R (SI_FREEBSD || SI_GLIBC || SI_SOLARIS)
> #define SANITIZER_INTERCEPT_SETPWENT \
> (SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
> #define SANITIZER_INTERCEPT_CLOCK_GETTIME \
> @@ -234,8 +238,8 @@
> #define SANITIZER_INTERCEPT_CLOCK_GETCPUCLOCKID SI_LINUX
> #define SANITIZER_INTERCEPT_GETITIMER SI_POSIX
> #define SANITIZER_INTERCEPT_TIME SI_POSIX
> -#define SANITIZER_INTERCEPT_GLOB SI_LINUX_NOT_ANDROID || SI_SOLARIS
> -#define SANITIZER_INTERCEPT_GLOB64 SI_LINUX_NOT_ANDROID
> +#define SANITIZER_INTERCEPT_GLOB (SI_GLIBC || SI_SOLARIS)
> +#define SANITIZER_INTERCEPT_GLOB64 SI_GLIBC
> #define SANITIZER_INTERCEPT_WAIT SI_POSIX
> #define SANITIZER_INTERCEPT_INET SI_POSIX
> #define SANITIZER_INTERCEPT_PTHREAD_GETSCHEDPARAM SI_POSIX
> @@ -250,8 +254,7 @@
> (SI_FREEBSD || SI_LINUX_NOT_ANDROID)
> #define SANITIZER_INTERCEPT_GETHOSTBYADDR_R \
> (SI_FREEBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
> -#define SANITIZER_INTERCEPT_GETHOSTENT_R \
> - (SI_FREEBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
> +#define SANITIZER_INTERCEPT_GETHOSTENT_R (SI_FREEBSD || SI_GLIBC || SI_SOLARIS)
> #define SANITIZER_INTERCEPT_GETSOCKOPT SI_POSIX
> #define SANITIZER_INTERCEPT_ACCEPT SI_POSIX
> #define SANITIZER_INTERCEPT_ACCEPT4 (SI_LINUX_NOT_ANDROID || SI_NETBSD)
> @@ -296,8 +299,7 @@
> (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
> #define SANITIZER_INTERCEPT_TCGETATTR SI_LINUX_NOT_ANDROID || SI_SOLARIS
> #define SANITIZER_INTERCEPT_REALPATH SI_POSIX
> -#define SANITIZER_INTERCEPT_CANONICALIZE_FILE_NAME \
> - (SI_LINUX_NOT_ANDROID || SI_SOLARIS)
> +#define SANITIZER_INTERCEPT_CANONICALIZE_FILE_NAME (SI_GLIBC || SI_SOLARIS)
> #define SANITIZER_INTERCEPT_CONFSTR \
> (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
> #define SANITIZER_INTERCEPT_SCHED_GETAFFINITY SI_LINUX_NOT_ANDROID
> @@ -324,7 +326,7 @@
> #define SANITIZER_INTERCEPT_SIGPROCMASK SI_POSIX
> #define SANITIZER_INTERCEPT_PTHREAD_SIGMASK SI_POSIX
> #define SANITIZER_INTERCEPT_BACKTRACE \
> - (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
> + (SI_FREEBSD || SI_NETBSD || SI_GLIBC || SI_SOLARIS)
> #define SANITIZER_INTERCEPT_GETMNTENT SI_LINUX
> #define SANITIZER_INTERCEPT_GETMNTENT_R SI_LINUX_NOT_ANDROID
> #define SANITIZER_INTERCEPT_STATFS \
> @@ -342,11 +344,11 @@
> #define SANITIZER_INTERCEPT_SHMCTL \
> (((SI_FREEBSD || SI_LINUX_NOT_ANDROID) && SANITIZER_WORDSIZE == 64) || \
> SI_NETBSD || SI_SOLARIS) // NOLINT
> -#define SANITIZER_INTERCEPT_RANDOM_R SI_LINUX_NOT_ANDROID
> +#define SANITIZER_INTERCEPT_RANDOM_R SI_GLIBC
> #define SANITIZER_INTERCEPT_PTHREAD_ATTR_GET SI_POSIX
> #define SANITIZER_INTERCEPT_PTHREAD_ATTR_GETINHERITSCHED \
> (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
> -#define SANITIZER_INTERCEPT_PTHREAD_ATTR_GETAFFINITY_NP SI_LINUX_NOT_ANDROID
> +#define SANITIZER_INTERCEPT_PTHREAD_ATTR_GETAFFINITY_NP SI_GLIBC
> #define SANITIZER_INTERCEPT_PTHREAD_ATTR_GET_SCHED SI_POSIX
> #define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPSHARED \
> (SI_POSIX && !SI_NETBSD)
> @@ -360,7 +362,7 @@
> #define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETROBUST_NP SI_LINUX_NOT_ANDROID
> #define SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GETPSHARED \
> (SI_POSIX && !SI_NETBSD)
> -#define SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GETKIND_NP SI_LINUX_NOT_ANDROID
> +#define SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GETKIND_NP SI_GLIBC
> #define SANITIZER_INTERCEPT_PTHREAD_CONDATTR_GETPSHARED (SI_POSIX && !SI_NETBSD)
> #define SANITIZER_INTERCEPT_PTHREAD_CONDATTR_GETCLOCK \
> (SI_LINUX_NOT_ANDROID || SI_SOLARIS)
> @@ -368,7 +370,7 @@
> (SI_LINUX_NOT_ANDROID && !SI_NETBSD)
> #define SANITIZER_INTERCEPT_THR_EXIT SI_FREEBSD
> #define SANITIZER_INTERCEPT_TMPNAM SI_POSIX
> -#define SANITIZER_INTERCEPT_TMPNAM_R SI_LINUX_NOT_ANDROID || SI_SOLARIS
> +#define SANITIZER_INTERCEPT_TMPNAM_R (SI_GLIBC || SI_SOLARIS)
> #define SANITIZER_INTERCEPT_PTSNAME SI_LINUX
> #define SANITIZER_INTERCEPT_PTSNAME_R SI_LINUX
> #define SANITIZER_INTERCEPT_TTYNAME SI_POSIX
> @@ -381,7 +383,7 @@
> #define SANITIZER_INTERCEPT_LGAMMAL (SI_POSIX && !SI_NETBSD)
> #define SANITIZER_INTERCEPT_LGAMMA_R (SI_FREEBSD || SI_LINUX || SI_SOLARIS)
> #define SANITIZER_INTERCEPT_LGAMMAL_R SI_LINUX_NOT_ANDROID || SI_SOLARIS
> -#define SANITIZER_INTERCEPT_DRAND48_R SI_LINUX_NOT_ANDROID
> +#define SANITIZER_INTERCEPT_DRAND48_R SI_GLIBC
> #define SANITIZER_INTERCEPT_RAND_R \
> (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
> #define SANITIZER_INTERCEPT_ICONV \
> @@ -396,12 +398,12 @@
> (SI_LINUX || SI_FREEBSD || SI_NETBSD || SI_MAC || SI_SOLARIS)
>
> #define SANITIZER_INTERCEPT_PTHREAD_MUTEX SI_POSIX
> -#define SANITIZER_INTERCEPT___PTHREAD_MUTEX SI_LINUX_NOT_ANDROID
> +#define SANITIZER_INTERCEPT___PTHREAD_MUTEX SI_GLIBC
> #define SANITIZER_INTERCEPT___LIBC_MUTEX SI_NETBSD
> #define SANITIZER_INTERCEPT_PTHREAD_SETNAME_NP \
> - (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
> + (SI_FREEBSD || SI_NETBSD || SI_GLIBC || SI_SOLARIS)
> #define SANITIZER_INTERCEPT_PTHREAD_GETNAME_NP \
> - (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
> + (SI_FREEBSD || SI_NETBSD || SI_GLIBC || SI_SOLARIS)
>
> #define SANITIZER_INTERCEPT_TLS_GET_ADDR \
> (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
> @@ -419,19 +421,19 @@
> #else
> #define SANITIZER_INTERCEPT_AEABI_MEM 0
> #endif
> -#define SANITIZER_INTERCEPT___BZERO SI_MAC || SI_LINUX_NOT_ANDROID
> +#define SANITIZER_INTERCEPT___BZERO SI_MAC || SI_GLIBC
> #define SANITIZER_INTERCEPT_BZERO SI_LINUX_NOT_ANDROID
> #define SANITIZER_INTERCEPT_FTIME (!SI_FREEBSD && !SI_NETBSD && SI_POSIX)
> -#define SANITIZER_INTERCEPT_XDR SI_LINUX_NOT_ANDROID || SI_SOLARIS
> -#define SANITIZER_INTERCEPT_XDRREC SI_LINUX_NOT_ANDROID
> +#define SANITIZER_INTERCEPT_XDR (SI_GLIBC || SI_SOLARIS)
> +#define SANITIZER_INTERCEPT_XDRREC SI_GLIBC
> #define SANITIZER_INTERCEPT_TSEARCH \
> (SI_LINUX_NOT_ANDROID || SI_MAC || SI_NETBSD || SI_SOLARIS)
> -#define SANITIZER_INTERCEPT_LIBIO_INTERNALS SI_LINUX_NOT_ANDROID
> +#define SANITIZER_INTERCEPT_LIBIO_INTERNALS SI_GLIBC
> #define SANITIZER_INTERCEPT_FOPEN SI_POSIX
> -#define SANITIZER_INTERCEPT_FOPEN64 SI_LINUX_NOT_ANDROID || SI_SOLARIS32
> +#define SANITIZER_INTERCEPT_FOPEN64 (SI_GLIBC || SI_SOLARIS32)
> #define SANITIZER_INTERCEPT_OPEN_MEMSTREAM \
> (SI_LINUX_NOT_ANDROID || SI_NETBSD || SI_SOLARIS)
> -#define SANITIZER_INTERCEPT_OBSTACK SI_LINUX_NOT_ANDROID
> +#define SANITIZER_INTERCEPT_OBSTACK SI_GLIBC
> #define SANITIZER_INTERCEPT_FFLUSH SI_POSIX
> #define SANITIZER_INTERCEPT_FCLOSE SI_POSIX
>
> @@ -456,7 +458,7 @@
> #define SANITIZER_INTERCEPT_CTERMID_R (SI_MAC || SI_FREEBSD || SI_SOLARIS)
>
> #define SANITIZER_INTERCEPTOR_HOOKS \
> - (SI_LINUX || SI_MAC || SI_WINDOWS || SI_NETBSD)
> + (SI_LINUX || SI_MAC || SI_WINDOWS || SI_FREEBSD || SI_NETBSD || SI_SOLARIS)
> #define SANITIZER_INTERCEPT_RECV_RECVFROM SI_POSIX
> #define SANITIZER_INTERCEPT_SEND_SENDTO SI_POSIX
> #define SANITIZER_INTERCEPT_EVENTFD_READ_WRITE SI_LINUX
> @@ -479,20 +481,12 @@
>
> #define SANITIZER_INTERCEPT_MMAP SI_POSIX
> #define SANITIZER_INTERCEPT_MMAP64 SI_LINUX_NOT_ANDROID
> -#define SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO \
> - (!SI_FREEBSD && !SI_MAC && !SI_NETBSD && SI_NOT_FUCHSIA && SI_NOT_RTEMS && \
> - !SI_SOLARIS) // NOLINT
> +#define SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO (SI_GLIBC || SI_ANDROID)
> #define SANITIZER_INTERCEPT_MEMALIGN \
> (!SI_FREEBSD && !SI_MAC && !SI_NETBSD && SI_NOT_RTEMS)
> -#define SANITIZER_INTERCEPT___LIBC_MEMALIGN \
> - (!SI_FREEBSD && !SI_MAC && !SI_NETBSD && !SI_OPENBSD && SI_NOT_RTEMS && \
> - !SI_ANDROID) // NOLINT
> -#define SANITIZER_INTERCEPT_PVALLOC \
> - (!SI_FREEBSD && !SI_MAC && !SI_NETBSD && SI_NOT_FUCHSIA && SI_NOT_RTEMS && \
> - !SI_SOLARIS) // NOLINT
> -#define SANITIZER_INTERCEPT_CFREE \
> - (!SI_FREEBSD && !SI_MAC && !SI_NETBSD && SI_NOT_FUCHSIA && SI_NOT_RTEMS && \
> - !SI_SOLARIS && !SANITIZER_ANDROID) // NOLINT
> +#define SANITIZER_INTERCEPT___LIBC_MEMALIGN SI_GLIBC
> +#define SANITIZER_INTERCEPT_PVALLOC (SI_GLIBC || SI_ANDROID)
> +#define SANITIZER_INTERCEPT_CFREE (SI_GLIBC && !SANITIZER_RISCV64)
> #define SANITIZER_INTERCEPT_REALLOCARRAY SI_POSIX
> #define SANITIZER_INTERCEPT_ALIGNED_ALLOC (!SI_MAC && SI_NOT_RTEMS)
> #define SANITIZER_INTERCEPT_MALLOC_USABLE_SIZE (!SI_MAC && !SI_NETBSD)
> @@ -532,7 +526,7 @@
> #define SANITIZER_INTERCEPT_STRMODE (SI_NETBSD || SI_FREEBSD)
> #define SANITIZER_INTERCEPT_TTYENT SI_NETBSD
> #define SANITIZER_INTERCEPT_PROTOENT (SI_NETBSD || SI_LINUX)
> -#define SANITIZER_INTERCEPT_PROTOENT_R (SI_LINUX_NOT_ANDROID)
> +#define SANITIZER_INTERCEPT_PROTOENT_R SI_GLIBC
> #define SANITIZER_INTERCEPT_NETENT SI_NETBSD
> #define SANITIZER_INTERCEPT_SETVBUF \
> (SI_NETBSD || SI_FREEBSD || SI_LINUX || SI_MAC)
> @@ -583,7 +577,7 @@
> #define SANITIZER_INTERCEPT_GETENTROPY SI_FREEBSD
> #define SANITIZER_INTERCEPT_QSORT \
> (SI_POSIX && !SI_IOSSIM && !SI_WATCHOS && !SI_TVOS && !SI_ANDROID)
> -#define SANITIZER_INTERCEPT_QSORT_R (SI_LINUX && !SI_ANDROID)
> +#define SANITIZER_INTERCEPT_QSORT_R SI_GLIBC
> // sigaltstack on i386 macOS cannot be intercepted due to setjmp()
> // calling it and assuming that it does not clobber registers.
> #define SANITIZER_INTERCEPT_SIGALTSTACK \
> @@ -591,4 +585,25 @@
> #define SANITIZER_INTERCEPT_UNAME (SI_POSIX && !SI_FREEBSD)
> #define SANITIZER_INTERCEPT___XUNAME SI_FREEBSD
>
> +// This macro gives a way for downstream users to override the above
> +// interceptor macros irrespective of the platform they are on. They have
> +// to do two things:
> +// 1. Build compiler-rt with -DSANITIZER_OVERRIDE_INTERCEPTORS.
> +// 2. Provide a header file named sanitizer_intercept_overriders.h in the
> +// include path for their compiler-rt build.
> +// An example of an overrider for strlen interceptor that one can list in
> +// sanitizer_intercept_overriders.h is as follows:
> +//
> +// #ifdef SANITIZER_INTERCEPT_STRLEN
> +// #undef SANITIZER_INTERCEPT_STRLEN
> +// #define SANITIZER_INTERCEPT_STRLEN <value of choice>
> +// #endif
> +//
> +// This "feature" is useful for downstream users who do not want some of
> +// their libc funtions to be intercepted. They can selectively disable
> +// interception of those functions.
> +#ifdef SANITIZER_OVERRIDE_INTERCEPTORS
> +#include <sanitizer_intercept_overriders.h>
> +#endif
> +
> #endif // #ifndef SANITIZER_PLATFORM_INTERCEPTORS_H
> diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.cpp b/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.cpp
> index b1c15be58de..b5a45ae72cd 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.cpp
> @@ -35,7 +35,10 @@
> #include <sys/stat.h>
> #include <sys/statvfs.h>
> #include <sys/time.h>
> +#pragma clang diagnostic push
> +#pragma clang diagnostic ignored "-W#warnings"
> #include <sys/timeb.h>
> +#pragma clang diagnostic pop
> #include <sys/times.h>
> #include <sys/timespec.h>
> #include <sys/types.h>
> diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cpp b/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cpp
> index f22f5039128..c51327e1269 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cpp
> @@ -26,12 +26,9 @@
>
> // 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. Beware that with <sys/stat.h>, struct stat
> -// takes the form of struct stat64 on 32-bit platforms if _FILE_OFFSET_BITS=64.
> -// Also, for some platforms (e.g. mips) there are additional members in the
> -// <sys/stat.h> struct stat:s.
> +// fine with newer headers, too.
> #include <linux/posix_types.h>
> -#if defined(__x86_64__)
> +#if defined(__x86_64__) || defined(__mips__)
> #include <sys/stat.h>
> #else
> #define ino_t __kernel_ino_t
> diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp
> index 1427cec48c4..35a690cba5c 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp
> @@ -11,18 +11,19 @@
> // Sizes and layouts of platform-specific POSIX data structures.
> //===----------------------------------------------------------------------===//
>
> -#include "sanitizer_platform.h"
> -
> -#if SANITIZER_LINUX || SANITIZER_MAC
> +#if defined(__linux__) || defined(__APPLE__)
> // Tests in this file assume that off_t-dependent data structures match the
> // libc ABI. For example, struct dirent here is what readdir() function (as
> // exported from libc) returns, and not the user-facing "dirent", which
> // depends on _FILE_OFFSET_BITS setting.
> // To get this "true" dirent definition, we undefine _FILE_OFFSET_BITS below.
> -#ifdef _FILE_OFFSET_BITS
> #undef _FILE_OFFSET_BITS
> #endif
>
> +// Must go after undef _FILE_OFFSET_BITS.
> +#include "sanitizer_platform.h"
> +
> +#if SANITIZER_LINUX || SANITIZER_MAC
> // Must go after undef _FILE_OFFSET_BITS.
> #include "sanitizer_glibc_version.h"
>
> @@ -37,6 +38,7 @@
> #include <pwd.h>
> #include <signal.h>
> #include <stddef.h>
> +#include <stdio.h>
> #include <sys/mman.h>
> #include <sys/resource.h>
> #include <sys/socket.h>
> @@ -58,7 +60,6 @@
> #endif
>
> #if !SANITIZER_ANDROID
> -#include <fstab.h>
> #include <sys/mount.h>
> #include <sys/timeb.h>
> #include <utmpx.h>
> @@ -110,20 +111,31 @@ typedef struct user_fpregs elf_fpregset_t;
> #include <wordexp.h>
> #endif
>
> -#if SANITIZER_LINUX && !SANITIZER_ANDROID
> -#include <glob.h>
> -#include <obstack.h>
> -#include <mqueue.h>
> +#if SANITIZER_LINUX
> +#if SANITIZER_GLIBC
> +#include <fstab.h>
> #include <net/if_ppp.h>
> #include <netax25/ax25.h>
> #include <netipx/ipx.h>
> #include <netrom/netrom.h>
> +#include <obstack.h>
> #if HAVE_RPC_XDR_H
> # include <rpc/xdr.h>
> #endif
> #include <scsi/scsi.h>
> -#include <sys/mtio.h>
> +#else
> +#include <linux/if_ppp.h>
> +#include <linux/kd.h>
> +#include <linux/ppp_defs.h>
> +#endif // SANITIZER_GLIBC
> +
> +#if SANITIZER_ANDROID
> +#include <linux/mtio.h>
> +#else
> +#include <glob.h>
> +#include <mqueue.h>
> #include <sys/kd.h>
> +#include <sys/mtio.h>
> #include <sys/shm.h>
> #include <sys/statvfs.h>
> #include <sys/timex.h>
> @@ -142,20 +154,14 @@ typedef struct user_fpregs elf_fpregset_t;
> #include <sys/msg.h>
> #include <sys/ipc.h>
> #include <crypt.h>
> -#endif // SANITIZER_LINUX && !SANITIZER_ANDROID
> +#endif // SANITIZER_ANDROID
>
> -#if SANITIZER_ANDROID
> -#include <linux/kd.h>
> -#include <linux/mtio.h>
> -#include <linux/ppp_defs.h>
> -#include <linux/if_ppp.h>
> -#endif
> -
> -#if SANITIZER_LINUX
> #include <link.h>
> #include <sys/vfs.h>
> #include <sys/epoll.h>
> #include <linux/capability.h>
> +#else
> +#include <fstab.h>
> #endif // SANITIZER_LINUX
>
> #if SANITIZER_MAC
> @@ -202,8 +208,11 @@ namespace __sanitizer {
> unsigned struct_statfs64_sz = sizeof(struct statfs64);
> #endif // (SANITIZER_MAC && !TARGET_CPU_ARM64) && !SANITIZER_IOS
>
> -#if !SANITIZER_ANDROID
> +#if SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_MAC
> unsigned struct_fstab_sz = sizeof(struct fstab);
> +#endif // SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD ||
> + // SANITIZER_MAC
> +#if !SANITIZER_ANDROID
> unsigned struct_statfs_sz = sizeof(struct statfs);
> unsigned struct_sockaddr_sz = sizeof(struct sockaddr);
> unsigned ucontext_t_sz = sizeof(ucontext_t);
> @@ -299,7 +308,7 @@ unsigned struct_ElfW_Phdr_sz = sizeof(ElfW(Phdr));
> unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
> #endif
>
> -#if SANITIZER_LINUX && !SANITIZER_ANDROID
> +#if SANITIZER_GLIBC
> int glob_nomatch = GLOB_NOMATCH;
> int glob_altdirfunc = GLOB_ALTDIRFUNC;
> #endif
> @@ -422,7 +431,9 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
> unsigned struct_input_id_sz = sizeof(struct input_id);
> unsigned struct_mtpos_sz = sizeof(struct mtpos);
> unsigned struct_rtentry_sz = sizeof(struct rtentry);
> +#if SANITIZER_GLIBC || SANITIZER_ANDROID
> unsigned struct_termio_sz = sizeof(struct termio);
> +#endif
> unsigned struct_vt_consize_sz = sizeof(struct vt_consize);
> unsigned struct_vt_sizes_sz = sizeof(struct vt_sizes);
> unsigned struct_vt_stat_sz = sizeof(struct vt_stat);
> @@ -447,7 +458,7 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
> unsigned struct_vt_mode_sz = sizeof(struct vt_mode);
> #endif // SANITIZER_LINUX
>
> -#if SANITIZER_LINUX && !SANITIZER_ANDROID
> +#if SANITIZER_GLIBC
> unsigned struct_ax25_parms_struct_sz = sizeof(struct ax25_parms_struct);
> unsigned struct_cyclades_monitor_sz = sizeof(struct cyclades_monitor);
> #if EV_VERSION > (0x010000)
> @@ -470,12 +481,10 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
> unsigned struct_sockaddr_ax25_sz = sizeof(struct sockaddr_ax25);
> unsigned struct_unimapdesc_sz = sizeof(struct unimapdesc);
> unsigned struct_unimapinit_sz = sizeof(struct unimapinit);
> -#endif // SANITIZER_LINUX && !SANITIZER_ANDROID
>
> -#if SANITIZER_LINUX && !SANITIZER_ANDROID
> unsigned struct_audio_buf_info_sz = sizeof(struct audio_buf_info);
> unsigned struct_ppp_stats_sz = sizeof(struct ppp_stats);
> -#endif // (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
> +#endif // SANITIZER_GLIBC
>
> #if !SANITIZER_ANDROID && !SANITIZER_MAC
> unsigned struct_sioc_sg_req_sz = sizeof(struct sioc_sg_req);
> @@ -881,6 +890,7 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
> unsigned IOCTL_PIO_UNIMAP = PIO_UNIMAP;
> unsigned IOCTL_PIO_UNIMAPCLR = PIO_UNIMAPCLR;
> unsigned IOCTL_PIO_UNISCRNMAP = PIO_UNISCRNMAP;
> +#if SANITIZER_GLIBC
> unsigned IOCTL_SCSI_IOCTL_GET_IDLUN = SCSI_IOCTL_GET_IDLUN;
> unsigned IOCTL_SCSI_IOCTL_PROBE_HOST = SCSI_IOCTL_PROBE_HOST;
> unsigned IOCTL_SCSI_IOCTL_TAGGED_DISABLE = SCSI_IOCTL_TAGGED_DISABLE;
> @@ -899,6 +909,7 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
> unsigned IOCTL_SIOCNRGETPARMS = SIOCNRGETPARMS;
> unsigned IOCTL_SIOCNRRTCTL = SIOCNRRTCTL;
> unsigned IOCTL_SIOCNRSETPARMS = SIOCNRSETPARMS;
> +#endif
> unsigned IOCTL_TIOCGSERIAL = TIOCGSERIAL;
> unsigned IOCTL_TIOCSERGETMULTI = TIOCSERGETMULTI;
> unsigned IOCTL_TIOCSERSETMULTI = TIOCSERSETMULTI;
> @@ -969,7 +980,7 @@ CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phdr);
> CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phnum);
> #endif // SANITIZER_LINUX || SANITIZER_FREEBSD
>
> -#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
> +#if SANITIZER_GLIBC || SANITIZER_FREEBSD
> CHECK_TYPE_SIZE(glob_t);
> CHECK_SIZE_AND_OFFSET(glob_t, gl_pathc);
> CHECK_SIZE_AND_OFFSET(glob_t, gl_pathv);
> @@ -980,7 +991,7 @@ CHECK_SIZE_AND_OFFSET(glob_t, gl_readdir);
> CHECK_SIZE_AND_OFFSET(glob_t, gl_opendir);
> CHECK_SIZE_AND_OFFSET(glob_t, gl_lstat);
> CHECK_SIZE_AND_OFFSET(glob_t, gl_stat);
> -#endif
> +#endif // SANITIZER_GLIBC || SANITIZER_FREEBSD
>
> CHECK_TYPE_SIZE(addrinfo);
> CHECK_SIZE_AND_OFFSET(addrinfo, ai_flags);
> @@ -1003,17 +1014,27 @@ CHECK_TYPE_SIZE(iovec);
> CHECK_SIZE_AND_OFFSET(iovec, iov_base);
> CHECK_SIZE_AND_OFFSET(iovec, iov_len);
>
> +// In POSIX, int msg_iovlen; socklen_t msg_controllen; socklen_t cmsg_len; but
> +// many implementations don't conform to the standard. Since we pick the
> +// non-conforming glibc definition, exclude the checks for musl (incompatible
> +// sizes but compatible offsets).
> CHECK_TYPE_SIZE(msghdr);
> CHECK_SIZE_AND_OFFSET(msghdr, msg_name);
> CHECK_SIZE_AND_OFFSET(msghdr, msg_namelen);
> CHECK_SIZE_AND_OFFSET(msghdr, msg_iov);
> +#if SANITIZER_GLIBC || SANITIZER_ANDROID
> CHECK_SIZE_AND_OFFSET(msghdr, msg_iovlen);
> +#endif
> CHECK_SIZE_AND_OFFSET(msghdr, msg_control);
> +#if SANITIZER_GLIBC || SANITIZER_ANDROID
> CHECK_SIZE_AND_OFFSET(msghdr, msg_controllen);
> +#endif
> CHECK_SIZE_AND_OFFSET(msghdr, msg_flags);
>
> CHECK_TYPE_SIZE(cmsghdr);
> +#if SANITIZER_GLIBC || SANITIZER_ANDROID
> CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_len);
> +#endif
> CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_level);
> CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_type);
>
> @@ -1121,7 +1142,7 @@ CHECK_SIZE_AND_OFFSET(mntent, mnt_passno);
>
> CHECK_TYPE_SIZE(ether_addr);
>
> -#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
> +#if SANITIZER_GLIBC || SANITIZER_FREEBSD
> CHECK_TYPE_SIZE(ipc_perm);
> # if SANITIZER_FREEBSD
> CHECK_SIZE_AND_OFFSET(ipc_perm, key);
> @@ -1183,7 +1204,7 @@ CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_dstaddr);
> CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_data);
> #endif
>
> -#if SANITIZER_LINUX
> +#if SANITIZER_GLIBC || SANITIZER_ANDROID
> COMPILER_CHECK(sizeof(__sanitizer_struct_mallinfo) == sizeof(struct mallinfo));
> #endif
>
> @@ -1233,7 +1254,7 @@ COMPILER_CHECK(__sanitizer_XDR_DECODE == XDR_DECODE);
> COMPILER_CHECK(__sanitizer_XDR_FREE == XDR_FREE);
> #endif
>
> -#if SANITIZER_LINUX && !SANITIZER_ANDROID
> +#if SANITIZER_GLIBC
> COMPILER_CHECK(sizeof(__sanitizer_FILE) <= sizeof(FILE));
> CHECK_SIZE_AND_OFFSET(FILE, _flags);
> CHECK_SIZE_AND_OFFSET(FILE, _IO_read_ptr);
> @@ -1250,9 +1271,7 @@ CHECK_SIZE_AND_OFFSET(FILE, _IO_save_end);
> CHECK_SIZE_AND_OFFSET(FILE, _markers);
> CHECK_SIZE_AND_OFFSET(FILE, _chain);
> CHECK_SIZE_AND_OFFSET(FILE, _fileno);
> -#endif
>
> -#if SANITIZER_LINUX && !SANITIZER_ANDROID
> COMPILER_CHECK(sizeof(__sanitizer__obstack_chunk) <= sizeof(_obstack_chunk));
> CHECK_SIZE_AND_OFFSET(_obstack_chunk, limit);
> CHECK_SIZE_AND_OFFSET(_obstack_chunk, prev);
> @@ -1267,7 +1286,7 @@ CHECK_SIZE_AND_OFFSET(cookie_io_functions_t, read);
> CHECK_SIZE_AND_OFFSET(cookie_io_functions_t, write);
> CHECK_SIZE_AND_OFFSET(cookie_io_functions_t, seek);
> CHECK_SIZE_AND_OFFSET(cookie_io_functions_t, close);
> -#endif
> +#endif // SANITIZER_GLIBC
>
> #if SANITIZER_LINUX || SANITIZER_FREEBSD
> CHECK_TYPE_SIZE(sem_t);
> diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h
> index 0812039b038..836b178c131 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h
> +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h
> @@ -83,7 +83,7 @@ const unsigned struct_kernel_stat64_sz = 104;
> #elif defined(__mips__)
> const unsigned struct_kernel_stat_sz = SANITIZER_ANDROID
> ? FIRST_32_SECOND_64(104, 128)
> - : FIRST_32_SECOND_64(144, 216);
> + : FIRST_32_SECOND_64(160, 216);
> const unsigned struct_kernel_stat64_sz = 104;
> #elif defined(__s390__) && !defined(__s390x__)
> const unsigned struct_kernel_stat_sz = 64;
> @@ -443,6 +443,8 @@ struct __sanitizer_cmsghdr {
> int cmsg_type;
> };
> #else
> +// In POSIX, int msg_iovlen; socklen_t msg_controllen; socklen_t cmsg_len; but
> +// many implementations don't conform to the standard.
> struct __sanitizer_msghdr {
> void *msg_name;
> unsigned msg_namelen;
> diff --git a/libsanitizer/sanitizer_common/sanitizer_posix.cpp b/libsanitizer/sanitizer_common/sanitizer_posix.cpp
> index 2e080098283..f8457a6aac4 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_posix.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_posix.cpp
> @@ -275,8 +275,8 @@ void ReportFile::Write(const char *buffer, uptr length) {
>
> bool GetCodeRangeForFile(const char *module, uptr *start, uptr *end) {
> MemoryMappingLayout proc_maps(/*cache_enabled*/false);
> - InternalScopedString buff(kMaxPathLength);
> - MemoryMappedSegment segment(buff.data(), kMaxPathLength);
> + InternalMmapVector<char> buff(kMaxPathLength);
> + MemoryMappedSegment segment(buff.data(), buff.size());
> while (proc_maps.Next(&segment)) {
> if (segment.IsExecutable() &&
> internal_strcmp(module, segment.filename) == 0) {
> diff --git a/libsanitizer/sanitizer_common/sanitizer_posix.h b/libsanitizer/sanitizer_common/sanitizer_posix.h
> index e1a2b48e5cd..b65dae64476 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_posix.h
> +++ b/libsanitizer/sanitizer_common/sanitizer_posix.h
> @@ -40,6 +40,10 @@ uptr internal_write(fd_t fd, const void *buf, uptr count);
> uptr internal_mmap(void *addr, uptr length, int prot, int flags,
> int fd, u64 offset);
> uptr internal_munmap(void *addr, uptr length);
> +#if SANITIZER_LINUX
> +uptr internal_mremap(void *old_address, uptr old_size, uptr new_size, int flags,
> + void *new_address);
> +#endif
> int internal_mprotect(void *addr, uptr length, int prot);
> int internal_madvise(uptr addr, uptr length, int advice);
>
> diff --git a/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp
> index 7ff48c35851..d1d8e509c4d 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp
> @@ -143,7 +143,7 @@ void Abort() {
> if (GetHandleSignalMode(SIGABRT) != kHandleSignalNo) {
> struct sigaction sigact;
> internal_memset(&sigact, 0, sizeof(sigact));
> - sigact.sa_sigaction = (sa_sigaction_t)SIG_DFL;
> + sigact.sa_handler = SIG_DFL;
> internal_sigaction(SIGABRT, &sigact, nullptr);
> }
> #endif
> diff --git a/libsanitizer/sanitizer_common/sanitizer_printf.cpp b/libsanitizer/sanitizer_common/sanitizer_printf.cpp
> index a032787114b..5d16dfde678 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_printf.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_printf.cpp
> @@ -249,26 +249,21 @@ static void NOINLINE SharedPrintfCodeNoBuffer(bool append_pid,
> va_list args) {
> va_list args2;
> va_copy(args2, args);
> - const int kLen = 16 * 1024;
> - int needed_length;
> + InternalMmapVector<char> v;
> + int needed_length = 0;
> char *buffer = local_buffer;
> // First try to print a message using a local buffer, and then fall back to
> // mmaped buffer.
> - for (int use_mmap = 0; use_mmap < 2; use_mmap++) {
> + for (int use_mmap = 0;; use_mmap++) {
> if (use_mmap) {
> va_end(args);
> va_copy(args, args2);
> - buffer = (char*)MmapOrDie(kLen, "Report");
> - buffer_size = kLen;
> + v.resize(needed_length + 1);
> + buffer_size = v.capacity();
> + v.resize(buffer_size);
> + buffer = &v[0];
> }
> needed_length = 0;
> - // Check that data fits into the current buffer.
> -# define CHECK_NEEDED_LENGTH \
> - if (needed_length >= buffer_size) { \
> - if (!use_mmap) continue; \
> - RAW_CHECK_MSG(needed_length < kLen, \
> - "Buffer in Report is too short!\n"); \
> - }
> // Fuchsia's logging infrastructure always keeps track of the logging
> // process, thread, and timestamp, so never prepend such information.
> if (!SANITIZER_FUCHSIA && append_pid) {
> @@ -277,18 +272,20 @@ static void NOINLINE SharedPrintfCodeNoBuffer(bool append_pid,
> if (common_flags()->log_exe_name && exe_name) {
> needed_length += internal_snprintf(buffer, buffer_size,
> "==%s", exe_name);
> - CHECK_NEEDED_LENGTH
> + if (needed_length >= buffer_size)
> + continue;
> }
> needed_length += internal_snprintf(
> buffer + needed_length, buffer_size - needed_length, "==%d==", pid);
> - CHECK_NEEDED_LENGTH
> + if (needed_length >= buffer_size)
> + continue;
> }
> needed_length += VSNPrintf(buffer + needed_length,
> buffer_size - needed_length, format, args);
> - CHECK_NEEDED_LENGTH
> + if (needed_length >= buffer_size)
> + continue;
> // If the message fit into the buffer, print it and exit.
> break;
> -# undef CHECK_NEEDED_LENGTH
> }
> RawWrite(buffer);
>
> @@ -297,9 +294,6 @@ static void NOINLINE SharedPrintfCodeNoBuffer(bool append_pid,
> CallPrintfAndReportCallback(buffer);
> LogMessageOnPrintf(buffer);
>
> - // If we had mapped any memory, clean up.
> - if (buffer != local_buffer)
> - UnmapOrDie((void *)buffer, buffer_size);
> va_end(args2);
> }
>
> @@ -346,13 +340,24 @@ int internal_snprintf(char *buffer, uptr length, const char *format, ...) {
>
> FORMAT(2, 3)
> 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_);
> - CHECK_LT(length_, size());
> + uptr prev_len = length();
> +
> + while (true) {
> + buffer_.resize(buffer_.capacity());
> +
> + va_list args;
> + va_start(args, format);
> + uptr sz = VSNPrintf(buffer_.data() + prev_len, buffer_.size() - prev_len,
> + format, args);
> + va_end(args);
> + if (sz < buffer_.size() - prev_len) {
> + buffer_.resize(prev_len + sz + 1);
> + break;
> + }
> +
> + buffer_.reserve(buffer_.capacity() * 2);
> + }
> + CHECK_EQ(buffer_[length()], '\0');
> }
>
> } // namespace __sanitizer
> diff --git a/libsanitizer/sanitizer_common/sanitizer_procmaps_common.cpp b/libsanitizer/sanitizer_common/sanitizer_procmaps_common.cpp
> index f2cfcffaf47..1b7dd46d8de 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_procmaps_common.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_procmaps_common.cpp
> @@ -120,7 +120,7 @@ void MemoryMappingLayout::LoadFromCache() {
> void MemoryMappingLayout::DumpListOfModules(
> InternalMmapVectorNoCtor<LoadedModule> *modules) {
> Reset();
> - InternalScopedString module_name(kMaxPathLength);
> + InternalMmapVector<char> module_name(kMaxPathLength);
> MemoryMappedSegment segment(module_name.data(), module_name.size());
> for (uptr i = 0; Next(&segment); i++) {
> const char *cur_name = segment.filename;
> diff --git a/libsanitizer/sanitizer_common/sanitizer_procmaps_mac.cpp b/libsanitizer/sanitizer_common/sanitizer_procmaps_mac.cpp
> index d02afcfe87a..1f53e3e46d8 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_procmaps_mac.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_procmaps_mac.cpp
> @@ -354,8 +354,8 @@ bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) {
> void MemoryMappingLayout::DumpListOfModules(
> InternalMmapVectorNoCtor<LoadedModule> *modules) {
> Reset();
> - InternalScopedString module_name(kMaxPathLength);
> - MemoryMappedSegment segment(module_name.data(), kMaxPathLength);
> + InternalMmapVector<char> module_name(kMaxPathLength);
> + MemoryMappedSegment segment(module_name.data(), module_name.size());
> MemoryMappedSegmentData data;
> segment.data_ = &data;
> while (Next(&segment)) {
> diff --git a/libsanitizer/sanitizer_common/sanitizer_procmaps_solaris.cpp b/libsanitizer/sanitizer_common/sanitizer_procmaps_solaris.cpp
> index 4063ec8deaa..bf813f235bb 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_procmaps_solaris.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_procmaps_solaris.cpp
> @@ -9,13 +9,13 @@
> // Information about the process mappings (Solaris-specific parts).
> //===----------------------------------------------------------------------===//
>
> +// Before Solaris 11.4, <procfs.h> doesn't work in a largefile environment.
> +#undef _FILE_OFFSET_BITS
> #include "sanitizer_platform.h"
> #if SANITIZER_SOLARIS
> #include "sanitizer_common.h"
> #include "sanitizer_procmaps.h"
>
> -// Before Solaris 11.4, <procfs.h> doesn't work in a largefile environment.
> -#undef _FILE_OFFSET_BITS
> #include <procfs.h>
> #include <limits.h>
>
> diff --git a/libsanitizer/sanitizer_common/sanitizer_ptrauth.h b/libsanitizer/sanitizer_common/sanitizer_ptrauth.h
> index a288068bf94..52003546948 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_ptrauth.h
> +++ b/libsanitizer/sanitizer_common/sanitizer_ptrauth.h
> @@ -11,6 +11,24 @@
>
> #if __has_feature(ptrauth_calls)
> #include <ptrauth.h>
> +#elif defined(__ARM_FEATURE_PAC_DEFAULT) && !defined(__APPLE__)
> +inline unsigned long ptrauth_strip(void* __value, unsigned int __key) {
> + // On the stack the link register is protected with Pointer
> + // Authentication Code when compiled with -mbranch-protection.
> + // Let's stripping the PAC unconditionally because xpaclri is in
> + // the NOP space so will do nothing when it is not enabled or not available.
> + unsigned long ret;
> + asm volatile(
> + "mov x30, %1\n\t"
> + "hint #7\n\t" // xpaclri
> + "mov %0, x30\n\t"
> + : "=r"(ret)
> + : "r"(__value)
> + : "x30");
> + return ret;
> +}
> +#define ptrauth_auth_data(__value, __old_key, __old_data) __value
> +#define ptrauth_string_discriminator(__string) ((int)0)
> #else
> // Copied from <ptrauth.h>
> #define ptrauth_strip(__value, __key) __value
> @@ -18,6 +36,6 @@
> #define ptrauth_string_discriminator(__string) ((int)0)
> #endif
>
> -#define STRIP_PC(pc) ((uptr)ptrauth_strip(pc, 0))
> +#define STRIP_PAC_PC(pc) ((uptr)ptrauth_strip(pc, 0))
>
> #endif // SANITIZER_PTRAUTH_H
> diff --git a/libsanitizer/sanitizer_common/sanitizer_stackdepot.cpp b/libsanitizer/sanitizer_common/sanitizer_stackdepot.cpp
> index 4692f50d323..44a95214e38 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_stackdepot.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_stackdepot.cpp
> @@ -145,8 +145,7 @@ StackTrace StackDepotReverseMap::Get(u32 id) {
> if (!map_.size())
> return StackTrace();
> IdDescPair pair = {id, nullptr};
> - uptr idx =
> - InternalLowerBound(map_, 0, map_.size(), pair, IdDescPair::IdComparator);
> + uptr idx = InternalLowerBound(map_, pair, IdDescPair::IdComparator);
> if (idx > map_.size() || map_[idx].id != id)
> return StackTrace();
> return map_[idx].desc->load();
> diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp b/libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp
> index b28fc1cf736..07e4409f4a5 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp
> @@ -15,6 +15,7 @@
> #include "sanitizer_common.h"
> #include "sanitizer_flags.h"
> #include "sanitizer_platform.h"
> +#include "sanitizer_ptrauth.h"
>
> namespace __sanitizer {
>
> @@ -84,8 +85,8 @@ static inline uhwptr *GetCanonicFrame(uptr bp,
> // Nope, this does not look right either. This means the frame after next does
> // not have a valid frame pointer, but we can still extract the caller PC.
> // Unfortunately, there is no way to decide between GCC and LLVM frame
> - // layouts. Assume GCC.
> - return bp_prev - 1;
> + // layouts. Assume LLVM.
> + return bp_prev;
> #else
> return (uhwptr*)bp;
> #endif
> @@ -108,28 +109,21 @@ void BufferedStackTrace::UnwindFast(uptr pc, uptr bp, uptr stack_top,
> IsAligned((uptr)frame, sizeof(*frame)) &&
> size < max_depth) {
> #ifdef __powerpc__
> - // PowerPC ABIs specify that the return address is saved on the
> - // *caller's* stack frame. Thus we must dereference the back chain
> - // to find the caller frame before extracting it.
> + // PowerPC ABIs specify that the return address is saved at offset
> + // 16 of the *caller's* stack frame. Thus we must dereference the
> + // back chain to find the caller frame before extracting it.
> uhwptr *caller_frame = (uhwptr*)frame[0];
> if (!IsValidFrame((uptr)caller_frame, stack_top, bottom) ||
> !IsAligned((uptr)caller_frame, sizeof(uhwptr)))
> break;
> - // For most ABIs the offset where the return address is saved is two
> - // register sizes. The exception is the SVR4 ABI, which uses an
> - // offset of only one register size.
> -#ifdef _CALL_SYSV
> - uhwptr pc1 = caller_frame[1];
> -#else
> uhwptr pc1 = caller_frame[2];
> -#endif
> #elif defined(__s390__)
> uhwptr pc1 = frame[14];
> #elif defined(__riscv)
> // frame[-1] contains the return address
> uhwptr pc1 = frame[-1];
> #else
> - uhwptr pc1 = frame[1];
> + uhwptr pc1 = STRIP_PAC_PC((void *)frame[1]);
> #endif
> // Let's assume that any pointer in the 0th page (i.e. <0x1000 on i386 and
> // x86_64) is invalid and stop unwinding here. If we're adding support for
> diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace.h b/libsanitizer/sanitizer_common/sanitizer_stacktrace.h
> index 0350fe84b04..15616f899d0 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_stacktrace.h
> +++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace.h
> @@ -67,8 +67,6 @@ struct StackTrace {
> static uptr GetCurrentPc();
> static inline uptr GetPreviousInstructionPc(uptr pc);
> static uptr GetNextInstructionPc(uptr pc);
> - typedef bool (*SymbolizeCallback)(const void *pc, char *out_buffer,
> - int out_size);
> };
>
> // Performance-critical, must be in the header.
> diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_stacktrace_libcdep.cpp
> index 7808ba9b0f5..738633209f0 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_stacktrace_libcdep.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace_libcdep.cpp
> @@ -23,8 +23,8 @@ void StackTrace::Print() const {
> Printf(" <empty stack>\n\n");
> return;
> }
> - InternalScopedString frame_desc(GetPageSizeCached() * 2);
> - InternalScopedString dedup_token(GetPageSizeCached());
> + InternalScopedString frame_desc;
> + InternalScopedString dedup_token;
> int dedup_frames = common_flags()->dedup_token_length;
> bool symbolize = RenderNeedsSymbolization(common_flags()->stack_trace_format);
> uptr frame_num = 0;
> @@ -125,7 +125,7 @@ void __sanitizer_symbolize_pc(uptr pc, const char *fmt, char *out_buf,
> out_buf[out_buf_size - 1] = 0;
> return;
> }
> - InternalScopedString frame_desc(GetPageSizeCached());
> + InternalScopedString frame_desc;
> uptr frame_num = 0;
> // Reserve one byte for the final 0.
> char *out_end = out_buf + out_buf_size - 1;
> @@ -156,7 +156,7 @@ void __sanitizer_symbolize_global(uptr data_addr, const char *fmt,
> out_buf[0] = 0;
> DataInfo DI;
> if (!Symbolizer::GetOrInit()->SymbolizeData(data_addr, &DI)) return;
> - InternalScopedString data_desc(GetPageSizeCached());
> + InternalScopedString data_desc;
> RenderData(&data_desc, fmt, &DI, common_flags()->strip_path_prefix);
> internal_strncpy(out_buf, data_desc.data(), out_buf_size);
> out_buf[out_buf_size - 1] = 0;
> diff --git a/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp
> index 0f1cadfeae3..53cfddcfbe0 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp
> @@ -490,6 +490,9 @@ typedef user_regs_struct regs_struct;
> #ifndef NT_X86_XSTATE
> #define NT_X86_XSTATE 0x202
> #endif
> +#ifndef PTRACE_GETREGSET
> +#define PTRACE_GETREGSET 0x4204
> +#endif
> // Compiler may use FP registers to store pointers.
> static constexpr uptr kExtraRegs[] = {NT_X86_XSTATE, NT_FPREGSET};
>
> @@ -513,6 +516,8 @@ static constexpr uptr kExtraRegs[] = {0};
>
> #elif SANITIZER_RISCV64
> typedef struct user_regs_struct regs_struct;
> +// sys/ucontext.h already defines REG_SP as 2. Undefine it first.
> +#undef REG_SP
> #define REG_SP sp
> static constexpr uptr kExtraRegs[] = {0};
> #define ARCH_IOVEC_FOR_GETREGSET
> diff --git a/libsanitizer/sanitizer_common/sanitizer_suppressions.cpp b/libsanitizer/sanitizer_common/sanitizer_suppressions.cpp
> index 44c83a66c5f..a674034b8e2 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_suppressions.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_suppressions.cpp
> @@ -34,7 +34,7 @@ SuppressionContext::SuppressionContext(const char *suppression_types[],
> static bool GetPathAssumingFileIsRelativeToExec(const char *file_path,
> /*out*/char *new_file_path,
> uptr new_file_path_size) {
> - InternalScopedString exec(kMaxPathLength);
> + InternalMmapVector<char> exec(kMaxPathLength);
> if (ReadBinaryNameCached(exec.data(), exec.size())) {
> const char *file_name_pos = StripModuleName(exec.data());
> uptr path_to_exec_len = file_name_pos - exec.data();
> @@ -69,7 +69,7 @@ void SuppressionContext::ParseFromFile(const char *filename) {
> if (filename[0] == '\0')
> return;
>
> - InternalScopedString new_file_path(kMaxPathLength);
> + InternalMmapVector<char> new_file_path(kMaxPathLength);
> filename = FindFile(filename, new_file_path.data(), new_file_path.size());
>
> // Read the file.
> diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cpp
> index 710da4c1cec..98418b426c3 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cpp
> @@ -356,7 +356,7 @@ void ParseSymbolizePCOutput(const char *str, SymbolizedStack *res) {
> InternalFree(info->function);
> info->function = 0;
> }
> - if (0 == internal_strcmp(info->file, "??")) {
> + if (info->file && 0 == internal_strcmp(info->file, "??")) {
> InternalFree(info->file);
> info->file = 0;
> }
> diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_markup.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_markup.cpp
> index 30cba08ed53..01edef9c1aa 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_markup.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_markup.cpp
> @@ -54,6 +54,10 @@ bool Symbolizer::GetModuleNameAndOffsetForPC(uptr pc, const char **module_name,
> return false;
> }
>
> +// This is mainly used by hwasan for online symbolization. This isn't needed
> +// since hwasan can always just dump stack frames for offline symbolization.
> +bool Symbolizer::SymbolizeFrame(uptr addr, FrameInfo *info) { return false; }
> +
> // This is used in some places for suppression checking, which we
> // don't really support for Fuchsia. It's also used in UBSan to
> // identify a PC location to a function name, so we always fill in
> diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp
> index 4dd5cc3ad7c..4cd4b4636f0 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp
> @@ -400,11 +400,20 @@ const char *Symbolizer::PlatformDemangle(const char *name) {
>
> static SymbolizerTool *ChooseExternalSymbolizer(LowLevelAllocator *allocator) {
> const char *path = common_flags()->external_symbolizer_path;
> +
> + if (path && internal_strchr(path, '%')) {
> + char *new_path = (char *)InternalAlloc(kMaxPathLength);
> + SubstituteForFlagValue(path, new_path, kMaxPathLength);
> + path = new_path;
> + }
> +
> const char *binary_name = path ? StripModuleName(path) : "";
> + static const char kLLVMSymbolizerPrefix[] = "llvm-symbolizer";
> if (path && path[0] == '\0') {
> VReport(2, "External symbolizer is explicitly disabled.\n");
> return nullptr;
> - } else if (!internal_strcmp(binary_name, "llvm-symbolizer")) {
> + } else if (!internal_strncmp(binary_name, kLLVMSymbolizerPrefix,
> + internal_strlen(kLLVMSymbolizerPrefix))) {
> VReport(2, "Using llvm-symbolizer at user-specified path: %s\n", path);
> return new(*allocator) LLVMSymbolizer(path, allocator);
> } else if (!internal_strcmp(binary_name, "atos")) {
> diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_report.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_report.cpp
> index 06301b83ea1..9287993e665 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_report.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_report.cpp
> @@ -31,7 +31,7 @@ namespace __sanitizer {
> void ReportErrorSummary(const char *error_type, const AddressInfo &info,
> const char *alt_tool_name) {
> if (!common_flags()->print_summary) return;
> - InternalScopedString buff(kMaxSummaryLength);
> + InternalScopedString buff;
> buff.append("%s ", error_type);
> RenderFrame(&buff, "%L %F", 0, info.address, &info,
> common_flags()->symbolize_vs_style,
> @@ -150,7 +150,7 @@ static void PrintMemoryByte(InternalScopedString *str, const char *before,
> static void MaybeDumpInstructionBytes(uptr pc) {
> if (!common_flags()->dump_instruction_bytes || (pc < GetPageSizeCached()))
> return;
> - InternalScopedString str(1024);
> + InternalScopedString str;
> str.append("First 16 instruction bytes at pc: ");
> if (IsAccessibleMemoryRange(pc, 16)) {
> for (int i = 0; i < 16; ++i) {
> @@ -211,7 +211,7 @@ static void ReportDeadlySignalImpl(const SignalContext &sig, u32 tid,
> Report("The signal is caused by a %s memory access.\n", access_type);
> if (!sig.is_true_faulting_addr)
> Report("Hint: this fault was caused by a dereference of a high value "
> - "address (see register values below). Dissassemble the provided "
> + "address (see register values below). Disassemble the provided "
> "pc to learn which register was used.\n");
> else if (sig.addr < GetPageSizeCached())
> Report("Hint: address points to the zero page.\n");
> diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cpp
> index 48fa2d1033a..702d901353d 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cpp
> @@ -136,9 +136,10 @@ void InitializeDbgHelpIfNeeded() {
> bool WinSymbolizerTool::SymbolizePC(uptr addr, SymbolizedStack *frame) {
> InitializeDbgHelpIfNeeded();
>
> - // See http://msdn.microsoft.com/en-us/library/ms680578(VS.85).aspx
> - char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(CHAR)];
> - PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer;
> + // See https://docs.microsoft.com/en-us/windows/win32/debug/retrieving-symbol-information-by-address
> + InternalMmapVector<char> buffer(sizeof(SYMBOL_INFO) +
> + MAX_SYM_NAME * sizeof(CHAR));
> + PSYMBOL_INFO symbol = (PSYMBOL_INFO)&buffer[0];
> symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
> symbol->MaxNameLen = MAX_SYM_NAME;
> DWORD64 offset = 0;
> @@ -223,7 +224,7 @@ bool SymbolizerProcess::StartSymbolizerSubprocess() {
> // Compute the command line. Wrap double quotes around everything.
> const char *argv[kArgVMax];
> GetArgV(path_, argv);
> - InternalScopedString command_line(kMaxPathLength * 3);
> + InternalScopedString command_line;
> for (int i = 0; argv[i]; i++) {
> const char *arg = argv[i];
> int arglen = internal_strlen(arg);
> @@ -281,8 +282,15 @@ static void ChooseSymbolizerTools(IntrusiveList<SymbolizerTool> *list,
> return;
> }
>
> - // Add llvm-symbolizer in case the binary has dwarf.
> + // Add llvm-symbolizer.
> const char *user_path = common_flags()->external_symbolizer_path;
> +
> + if (user_path && internal_strchr(user_path, '%')) {
> + char *new_path = (char *)InternalAlloc(kMaxPathLength);
> + SubstituteForFlagValue(user_path, new_path, kMaxPathLength);
> + user_path = new_path;
> + }
> +
> const char *path =
> user_path ? user_path : FindPathToBinary("llvm-symbolizer.exe");
> if (path) {
> diff --git a/libsanitizer/sanitizer_common/sanitizer_termination.cpp b/libsanitizer/sanitizer_common/sanitizer_termination.cpp
> index 84be6fc3234..6a54734353c 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_termination.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_termination.cpp
> @@ -59,26 +59,31 @@ void NORETURN Die() {
> internal__exit(common_flags()->exitcode);
> }
>
> -static CheckFailedCallbackType CheckFailedCallback;
> -void SetCheckFailedCallback(CheckFailedCallbackType callback) {
> - CheckFailedCallback = callback;
> +static void (*CheckUnwindCallback)();
> +void SetCheckUnwindCallback(void (*callback)()) {
> + CheckUnwindCallback = callback;
> }
>
> -const int kSecondsToSleepWhenRecursiveCheckFailed = 2;
> -
> void NORETURN CheckFailed(const char *file, int line, const char *cond,
> u64 v1, u64 v2) {
> - static atomic_uint32_t num_calls;
> - if (atomic_fetch_add(&num_calls, 1, memory_order_relaxed) > 10) {
> - SleepForSeconds(kSecondsToSleepWhenRecursiveCheckFailed);
> + u32 tid = GetTid();
> + Printf("%s: CHECK failed: %s:%d \"%s\" (0x%zx, 0x%zx) (tid=%u)\n",
> + SanitizerToolName, StripModuleName(file), line, cond, (uptr)v1,
> + (uptr)v2, tid);
> + static atomic_uint32_t first_tid;
> + u32 cmp = 0;
> + if (!atomic_compare_exchange_strong(&first_tid, &cmp, tid,
> + memory_order_relaxed)) {
> + if (cmp == tid) {
> + // Recursing into CheckFailed.
> + } else {
> + // Another thread fails already, let it print the stack and terminate.
> + SleepForSeconds(2);
> + }
> Trap();
> }
> -
> - if (CheckFailedCallback) {
> - CheckFailedCallback(file, line, cond, v1, v2);
> - }
> - Report("Sanitizer CHECK failed: %s:%d %s (%lld, %lld)\n", file, line, cond,
> - v1, v2);
> + if (CheckUnwindCallback)
> + CheckUnwindCallback();
> Die();
> }
>
> diff --git a/libsanitizer/sanitizer_common/sanitizer_thread_registry.cpp b/libsanitizer/sanitizer_common/sanitizer_thread_registry.cpp
> index f2c6f279931..3273da38bfd 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_thread_registry.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_thread_registry.cpp
> @@ -85,7 +85,7 @@ void ThreadContextBase::SetCreated(uptr _user_id, u64 _unique_id,
> unique_id = _unique_id;
> detached = _detached;
> // Parent tid makes no sense for the main thread.
> - if (tid != 0)
> + if (tid != kMainTid)
> parent_tid = _parent_tid;
> OnCreated(arg);
> }
> @@ -99,8 +99,6 @@ void ThreadContextBase::Reset() {
>
> // ThreadRegistry implementation.
>
> -const u32 ThreadRegistry::kUnknownTid = ~0U;
> -
> ThreadRegistry::ThreadRegistry(ThreadContextFactory factory, u32 max_threads,
> u32 thread_quarantine_size, u32 max_reuse)
> : context_factory_(factory),
> @@ -135,7 +133,7 @@ uptr ThreadRegistry::GetMaxAliveThreads() {
> u32 ThreadRegistry::CreateThread(uptr user_id, bool detached, u32 parent_tid,
> void *arg) {
> BlockingMutexLock l(&mtx_);
> - u32 tid = kUnknownTid;
> + u32 tid = kInvalidTid;
> ThreadContextBase *tctx = QuarantinePop();
> if (tctx) {
> tid = tctx->tid;
> @@ -155,7 +153,7 @@ u32 ThreadRegistry::CreateThread(uptr user_id, bool detached, u32 parent_tid,
> Die();
> }
> CHECK_NE(tctx, 0);
> - CHECK_NE(tid, kUnknownTid);
> + CHECK_NE(tid, kInvalidTid);
> CHECK_LT(tid, max_threads_);
> CHECK_EQ(tctx->status, ThreadStatusInvalid);
> alive_threads_++;
> @@ -186,7 +184,7 @@ u32 ThreadRegistry::FindThread(FindThreadCallback cb, void *arg) {
> if (tctx != 0 && cb(tctx, arg))
> return tctx->tid;
> }
> - return kUnknownTid;
> + return kInvalidTid;
> }
>
> ThreadContextBase *
> @@ -278,7 +276,7 @@ void ThreadRegistry::JoinThread(u32 tid, void *arg) {
> // really started. We just did CreateThread for a prospective new
> // thread before trying to create it, and then failed to actually
> // create it, and so never called StartThread.
> -void ThreadRegistry::FinishThread(u32 tid) {
> +ThreadStatus ThreadRegistry::FinishThread(u32 tid) {
> BlockingMutexLock l(&mtx_);
> CHECK_GT(alive_threads_, 0);
> alive_threads_--;
> @@ -286,6 +284,7 @@ void ThreadRegistry::FinishThread(u32 tid) {
> ThreadContextBase *tctx = threads_[tid];
> CHECK_NE(tctx, 0);
> bool dead = tctx->detached;
> + ThreadStatus prev_status = tctx->status;
> if (tctx->status == ThreadStatusRunning) {
> CHECK_GT(running_threads_, 0);
> running_threads_--;
> @@ -300,6 +299,7 @@ void ThreadRegistry::FinishThread(u32 tid) {
> QuarantinePush(tctx);
> }
> tctx->SetDestroyed();
> + return prev_status;
> }
>
> void ThreadRegistry::StartThread(u32 tid, tid_t os_id, ThreadType thread_type,
> diff --git a/libsanitizer/sanitizer_common/sanitizer_thread_registry.h b/libsanitizer/sanitizer_common/sanitizer_thread_registry.h
> index 85c522a31ca..dcd445c28ae 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_thread_registry.h
> +++ b/libsanitizer/sanitizer_common/sanitizer_thread_registry.h
> @@ -87,8 +87,6 @@ typedef ThreadContextBase* (*ThreadContextFactory)(u32 tid);
>
> class ThreadRegistry {
> public:
> - static const u32 kUnknownTid;
> -
> ThreadRegistry(ThreadContextFactory factory, u32 max_threads,
> u32 thread_quarantine_size, u32 max_reuse = 0);
> void GetNumberOfThreads(uptr *total = nullptr, uptr *running = nullptr,
> @@ -113,7 +111,7 @@ class ThreadRegistry {
> void RunCallbackForEachThreadLocked(ThreadCallback cb, void *arg);
>
> typedef bool (*FindThreadCallback)(ThreadContextBase *tctx, void *arg);
> - // Finds a thread using the provided callback. Returns kUnknownTid if no
> + // Finds a thread using the provided callback. Returns kInvalidTid if no
> // thread is found.
> u32 FindThread(FindThreadCallback cb, void *arg);
> // Should be guarded by ThreadRegistryLock. Return 0 if no thread
> @@ -126,7 +124,8 @@ class ThreadRegistry {
> void SetThreadNameByUserId(uptr user_id, const char *name);
> void DetachThread(u32 tid, void *arg);
> void JoinThread(u32 tid, void *arg);
> - void FinishThread(u32 tid);
> + // Finishes thread and returns previous status.
> + ThreadStatus FinishThread(u32 tid);
> void StartThread(u32 tid, tid_t os_id, ThreadType thread_type, void *arg);
> void SetThreadUserId(u32 tid, uptr user_id);
>
> diff --git a/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.cpp b/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.cpp
> index 10748f96420..1f664b6cf5b 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.cpp
> @@ -12,6 +12,7 @@
>
> #include "sanitizer_tls_get_addr.h"
>
> +#include "sanitizer_atomic.h"
> #include "sanitizer_flags.h"
> #include "sanitizer_platform_interceptors.h"
>
> @@ -42,39 +43,54 @@ static atomic_uintptr_t number_of_live_dtls;
>
> static const uptr kDestroyedThread = -1;
>
> -static inline void DTLS_Deallocate(DTLS::DTV *dtv, uptr size) {
> - if (!size) return;
> - VReport(2, "__tls_get_addr: DTLS_Deallocate %p %zd\n", dtv, size);
> - UnmapOrDie(dtv, size * sizeof(DTLS::DTV));
> +static void DTLS_Deallocate(DTLS::DTVBlock *block) {
> + VReport(2, "__tls_get_addr: DTLS_Deallocate %p %zd\n", block);
> + UnmapOrDie(block, sizeof(DTLS::DTVBlock));
> atomic_fetch_sub(&number_of_live_dtls, 1, memory_order_relaxed);
> }
>
> -static inline void DTLS_Resize(uptr new_size) {
> - if (dtls.dtv_size >= new_size) return;
> - new_size = RoundUpToPowerOfTwo(new_size);
> - new_size = Max(new_size, 4096UL / sizeof(DTLS::DTV));
> - DTLS::DTV *new_dtv =
> - (DTLS::DTV *)MmapOrDie(new_size * sizeof(DTLS::DTV), "DTLS_Resize");
> +static DTLS::DTVBlock *DTLS_NextBlock(atomic_uintptr_t *cur) {
> + uptr v = atomic_load(cur, memory_order_acquire);
> + if (v == kDestroyedThread)
> + return nullptr;
> + DTLS::DTVBlock *next = (DTLS::DTVBlock *)v;
> + if (next)
> + return next;
> + DTLS::DTVBlock *new_dtv =
> + (DTLS::DTVBlock *)MmapOrDie(sizeof(DTLS::DTVBlock), "DTLS_NextBlock");
> + uptr prev = 0;
> + if (!atomic_compare_exchange_strong(cur, &prev, (uptr)new_dtv,
> + memory_order_seq_cst)) {
> + UnmapOrDie(new_dtv, sizeof(DTLS::DTVBlock));
> + return (DTLS::DTVBlock *)prev;
> + }
> uptr num_live_dtls =
> atomic_fetch_add(&number_of_live_dtls, 1, memory_order_relaxed);
> - VReport(2, "__tls_get_addr: DTLS_Resize %p %zd\n", &dtls, num_live_dtls);
> - CHECK_LT(num_live_dtls, 1 << 20);
> - uptr old_dtv_size = dtls.dtv_size;
> - DTLS::DTV *old_dtv = dtls.dtv;
> - if (old_dtv_size)
> - internal_memcpy(new_dtv, dtls.dtv, dtls.dtv_size * sizeof(DTLS::DTV));
> - dtls.dtv = new_dtv;
> - dtls.dtv_size = new_size;
> - if (old_dtv_size)
> - DTLS_Deallocate(old_dtv, old_dtv_size);
> + VReport(2, "__tls_get_addr: DTLS_NextBlock %p %zd\n", &dtls, num_live_dtls);
> + return new_dtv;
> +}
> +
> +static DTLS::DTV *DTLS_Find(uptr id) {
> + VReport(2, "__tls_get_addr: DTLS_Find %p %zd\n", &dtls, id);
> + static constexpr uptr kPerBlock = ARRAY_SIZE(DTLS::DTVBlock::dtvs);
> + DTLS::DTVBlock *cur = DTLS_NextBlock(&dtls.dtv_block);
> + if (!cur)
> + return nullptr;
> + for (; id >= kPerBlock; id -= kPerBlock) cur = DTLS_NextBlock(&cur->next);
> + return cur->dtvs + id;
> }
>
> void DTLS_Destroy() {
> if (!common_flags()->intercept_tls_get_addr) return;
> - VReport(2, "__tls_get_addr: DTLS_Destroy %p %zd\n", &dtls, dtls.dtv_size);
> - uptr s = dtls.dtv_size;
> - dtls.dtv_size = kDestroyedThread; // Do this before unmap for AS-safety.
> - DTLS_Deallocate(dtls.dtv, s);
> + VReport(2, "__tls_get_addr: DTLS_Destroy %p\n", &dtls);
> + DTLS::DTVBlock *block = (DTLS::DTVBlock *)atomic_exchange(
> + &dtls.dtv_block, kDestroyedThread, memory_order_release);
> + while (block) {
> + DTLS::DTVBlock *next =
> + (DTLS::DTVBlock *)atomic_load(&block->next, memory_order_acquire);
> + DTLS_Deallocate(block);
> + block = next;
> + }
> }
>
> #if defined(__powerpc64__) || defined(__mips__)
> @@ -96,9 +112,9 @@ DTLS::DTV *DTLS_on_tls_get_addr(void *arg_void, void *res,
> if (!common_flags()->intercept_tls_get_addr) return 0;
> TlsGetAddrParam *arg = reinterpret_cast<TlsGetAddrParam *>(arg_void);
> uptr dso_id = arg->dso_id;
> - if (dtls.dtv_size == kDestroyedThread) return 0;
> - DTLS_Resize(dso_id + 1);
> - if (dtls.dtv[dso_id].beg) return 0;
> + DTLS::DTV *dtv = DTLS_Find(dso_id);
> + if (!dtv || dtv->beg)
> + return 0;
> uptr tls_size = 0;
> uptr tls_beg = reinterpret_cast<uptr>(res) - arg->offset - kDtvOffset;
> VReport(2, "__tls_get_addr: %p {%p,%p} => %p; tls_beg: %p; sp: %p "
> @@ -126,9 +142,9 @@ DTLS::DTV *DTLS_on_tls_get_addr(void *arg_void, void *res,
> // This may happen inside the DTOR of main thread, so just ignore it.
> tls_size = 0;
> }
> - dtls.dtv[dso_id].beg = tls_beg;
> - dtls.dtv[dso_id].size = tls_size;
> - return dtls.dtv + dso_id;
> + dtv->beg = tls_beg;
> + dtv->size = tls_size;
> + return dtv;
> }
>
> void DTLS_on_libc_memalign(void *ptr, uptr size) {
> @@ -141,7 +157,8 @@ void DTLS_on_libc_memalign(void *ptr, uptr size) {
> DTLS *DTLS_Get() { return &dtls; }
>
> bool DTLSInDestruction(DTLS *dtls) {
> - return dtls->dtv_size == kDestroyedThread;
> + return atomic_load(&dtls->dtv_block, memory_order_relaxed) ==
> + kDestroyedThread;
> }
>
> #else
> diff --git a/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.h b/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.h
> index c7cd5a8bffc..a599c0bbc75 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.h
> +++ b/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.h
> @@ -28,6 +28,7 @@
> #ifndef SANITIZER_TLS_GET_ADDR_H
> #define SANITIZER_TLS_GET_ADDR_H
>
> +#include "sanitizer_atomic.h"
> #include "sanitizer_common.h"
>
> namespace __sanitizer {
> @@ -38,15 +39,31 @@ struct DTLS {
> struct DTV {
> uptr beg, size;
> };
> + struct DTVBlock {
> + atomic_uintptr_t next;
> + DTV dtvs[(4096UL - sizeof(next)) / sizeof(DTLS::DTV)];
> + };
> +
> + static_assert(sizeof(DTVBlock) <= 4096UL, "Unexpected block size");
>
> - uptr dtv_size;
> - DTV *dtv; // dtv_size elements, allocated by MmapOrDie.
> + atomic_uintptr_t dtv_block;
>
> // Auxiliary fields, don't access them outside sanitizer_tls_get_addr.cpp
> uptr last_memalign_size;
> uptr last_memalign_ptr;
> };
>
> +template <typename Fn>
> +void ForEachDVT(DTLS *dtls, const Fn &fn) {
> + DTLS::DTVBlock *block =
> + (DTLS::DTVBlock *)atomic_load(&dtls->dtv_block, memory_order_acquire);
> + while (block) {
> + int id = 0;
> + for (auto &d : block->dtvs) fn(d, id++);
> + block = (DTLS::DTVBlock *)atomic_load(&block->next, memory_order_acquire);
> + }
> +}
> +
> // Returns pointer and size of a linker-allocated TLS block.
> // Each block is returned exactly once.
> DTLS::DTV *DTLS_on_tls_get_addr(void *arg, void *res, uptr static_tls_begin,
> diff --git a/libsanitizer/sanitizer_common/sanitizer_unwind_win.cpp b/libsanitizer/sanitizer_common/sanitizer_unwind_win.cpp
> index e2edf428004..7e01c81d042 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_unwind_win.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_unwind_win.cpp
> @@ -43,6 +43,10 @@ void BufferedStackTrace::UnwindSlow(uptr pc, u32 max_depth) {
> trace_buffer[0] = pc;
> }
>
> +#ifdef __clang__
> +#pragma clang diagnostic push
> +#pragma clang diagnostic ignored "-Wframe-larger-than="
> +#endif
> void BufferedStackTrace::UnwindSlow(uptr pc, void *context, u32 max_depth) {
> CHECK(context);
> CHECK_GE(max_depth, 2);
> @@ -74,6 +78,9 @@ void BufferedStackTrace::UnwindSlow(uptr pc, void *context, u32 max_depth) {
> trace_buffer[size++] = (uptr)stack_frame.AddrPC.Offset;
> }
> }
> +#ifdef __clang__
> +#pragma clang diagnostic pop
> +#endif
> #endif // #if !SANITIZER_GO
>
> #endif // SANITIZER_WINDOWS
> diff --git a/libsanitizer/sanitizer_common/sanitizer_win.cpp b/libsanitizer/sanitizer_common/sanitizer_win.cpp
> index 85ac2633bde..f383e130fa5 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_win.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_win.cpp
> @@ -334,8 +334,12 @@ bool MprotectNoAccess(uptr addr, uptr size) {
> }
>
> void ReleaseMemoryPagesToOS(uptr beg, uptr end) {
> - // This is almost useless on 32-bits.
> - // FIXME: add madvise-analog when we move to 64-bits.
> + uptr beg_aligned = RoundDownTo(beg, GetPageSizeCached()),
> + end_aligned = RoundDownTo(end, GetPageSizeCached());
> + CHECK(beg < end); // make sure the region is sane
> + if (beg_aligned == end_aligned) // make sure we're freeing at least 1 page;
> + return;
> + UnmapOrDie((void *)beg, end_aligned - beg_aligned);
> }
>
> void SetShadowRegionHugePageMode(uptr addr, uptr size) {
> @@ -386,6 +390,12 @@ uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding,
> return 0;
> }
>
> +uptr MapDynamicShadowAndAliases(uptr shadow_size, uptr alias_size,
> + uptr num_aliases, uptr ring_buffer_size) {
> + CHECK(false && "HWASan aliasing is unimplemented on Windows");
> + return 0;
> +}
> +
> bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) {
> MEMORY_BASIC_INFORMATION mbi;
> CHECK(VirtualQuery((void *)range_start, &mbi, sizeof(mbi)));
> @@ -564,7 +574,7 @@ void Abort() {
> // load the image at this address. Therefore, we call it the preferred base. Any
> // addresses in the DWARF typically assume that the object has been loaded at
> // this address.
> -static uptr GetPreferredBase(const char *modname) {
> +static uptr GetPreferredBase(const char *modname, char *buf, size_t buf_size) {
> fd_t fd = OpenFile(modname, RdOnly, nullptr);
> if (fd == kInvalidFd)
> return 0;
> @@ -586,12 +596,10 @@ static uptr GetPreferredBase(const char *modname) {
> // IMAGE_FILE_HEADER
> // IMAGE_OPTIONAL_HEADER
> // Seek to e_lfanew and read all that data.
> - char buf[4 + sizeof(IMAGE_FILE_HEADER) + sizeof(IMAGE_OPTIONAL_HEADER)];
> if (::SetFilePointer(fd, dos_header.e_lfanew, nullptr, FILE_BEGIN) ==
> INVALID_SET_FILE_POINTER)
> return 0;
> - if (!ReadFromFile(fd, &buf[0], sizeof(buf), &bytes_read) ||
> - bytes_read != sizeof(buf))
> + if (!ReadFromFile(fd, buf, buf_size, &bytes_read) || bytes_read != buf_size)
> return 0;
>
> // Check for "PE\0\0" before the PE header.
> @@ -633,6 +641,10 @@ void ListOfModules::init() {
> }
> }
>
> + InternalMmapVector<char> buf(4 + sizeof(IMAGE_FILE_HEADER) +
> + sizeof(IMAGE_OPTIONAL_HEADER));
> + InternalMmapVector<wchar_t> modname_utf16(kMaxPathLength);
> + InternalMmapVector<char> module_name(kMaxPathLength);
> // |num_modules| is the number of modules actually present,
> size_t num_modules = bytes_required / sizeof(HMODULE);
> for (size_t i = 0; i < num_modules; ++i) {
> @@ -642,15 +654,13 @@ void ListOfModules::init() {
> continue;
>
> // Get the UTF-16 path and convert to UTF-8.
> - wchar_t modname_utf16[kMaxPathLength];
> int modname_utf16_len =
> - GetModuleFileNameW(handle, modname_utf16, kMaxPathLength);
> + GetModuleFileNameW(handle, &modname_utf16[0], kMaxPathLength);
> if (modname_utf16_len == 0)
> modname_utf16[0] = '\0';
> - char module_name[kMaxPathLength];
> - int module_name_len =
> - ::WideCharToMultiByte(CP_UTF8, 0, modname_utf16, modname_utf16_len + 1,
> - &module_name[0], kMaxPathLength, NULL, NULL);
> + int module_name_len = ::WideCharToMultiByte(
> + CP_UTF8, 0, &modname_utf16[0], modname_utf16_len + 1, &module_name[0],
> + kMaxPathLength, NULL, NULL);
> module_name[module_name_len] = '\0';
>
> uptr base_address = (uptr)mi.lpBaseOfDll;
> @@ -660,15 +670,16 @@ void ListOfModules::init() {
> // RVA when computing the module offset. This helps llvm-symbolizer find the
> // right DWARF CU. In the common case that the image is loaded at it's
> // preferred address, we will now print normal virtual addresses.
> - uptr preferred_base = GetPreferredBase(&module_name[0]);
> + uptr preferred_base =
> + GetPreferredBase(&module_name[0], &buf[0], buf.size());
> uptr adjusted_base = base_address - preferred_base;
>
> - LoadedModule cur_module;
> - cur_module.set(module_name, adjusted_base);
> + modules_.push_back(LoadedModule());
> + LoadedModule &cur_module = modules_.back();
> + cur_module.set(&module_name[0], adjusted_base);
> // We add the whole module as one single address range.
> cur_module.addAddressRange(base_address, end_address, /*executable*/ true,
> /*writable*/ true);
> - modules_.push_back(cur_module);
> }
> UnmapOrDie(hmodules, modules_buffer_size);
> }
> @@ -956,22 +967,27 @@ void SignalContext::InitPcSpBp() {
>
> uptr SignalContext::GetAddress() const {
> EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD *)siginfo;
> - return exception_record->ExceptionInformation[1];
> + if (exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
> + return exception_record->ExceptionInformation[1];
> + return (uptr)exception_record->ExceptionAddress;
> }
>
> bool SignalContext::IsMemoryAccess() const {
> - return GetWriteFlag() != SignalContext::UNKNOWN;
> + return ((EXCEPTION_RECORD *)siginfo)->ExceptionCode ==
> + EXCEPTION_ACCESS_VIOLATION;
> }
>
> -bool SignalContext::IsTrueFaultingAddress() const {
> - // FIXME: Provide real implementation for this. See Linux and Mac variants.
> - return IsMemoryAccess();
> -}
> +bool SignalContext::IsTrueFaultingAddress() const { return true; }
>
> SignalContext::WriteFlag SignalContext::GetWriteFlag() const {
> EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD *)siginfo;
> +
> + // The write flag is only available for access violation exceptions.
> + if (exception_record->ExceptionCode != EXCEPTION_ACCESS_VIOLATION)
> + return SignalContext::UNKNOWN;
> +
> // The contents of this array are documented at
> - // https://msdn.microsoft.com/en-us/library/windows/desktop/aa363082(v=vs.85).aspx
> + // https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-exception_record
> // The first element indicates read as 0, write as 1, or execute as 8. The
> // second element is the faulting address.
> switch (exception_record->ExceptionInformation[0]) {
> @@ -1037,10 +1053,24 @@ const char *SignalContext::Describe() const {
> }
>
> uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {
> - // FIXME: Actually implement this function.
> - CHECK_GT(buf_len, 0);
> - buf[0] = 0;
> - return 0;
> + if (buf_len == 0)
> + return 0;
> +
> + // Get the UTF-16 path and convert to UTF-8.
> + InternalMmapVector<wchar_t> binname_utf16(kMaxPathLength);
> + int binname_utf16_len =
> + GetModuleFileNameW(NULL, &binname_utf16[0], kMaxPathLength);
> + if (binname_utf16_len == 0) {
> + buf[0] = '\0';
> + return 0;
> + }
> + int binary_name_len =
> + ::WideCharToMultiByte(CP_UTF8, 0, &binname_utf16[0], binname_utf16_len,
> + buf, buf_len, NULL, NULL);
> + if ((unsigned)binary_name_len == buf_len)
> + --binary_name_len;
> + buf[binary_name_len] = '\0';
> + return binary_name_len;
> }
>
> uptr ReadLongProcessName(/*out*/char *buf, uptr buf_len) {
> diff --git a/libsanitizer/tsan/tsan_clock.cpp b/libsanitizer/tsan/tsan_clock.cpp
> index c91b29cb22b..8e5188392ca 100644
> --- a/libsanitizer/tsan/tsan_clock.cpp
> +++ b/libsanitizer/tsan/tsan_clock.cpp
> @@ -150,7 +150,7 @@ void ThreadClock::acquire(ClockCache *c, SyncClock *src) {
> bool acquired = false;
> for (unsigned i = 0; i < kDirtyTids; i++) {
> SyncClock::Dirty dirty = src->dirty_[i];
> - unsigned tid = dirty.tid;
> + unsigned tid = dirty.tid();
> if (tid != kInvalidTid) {
> if (clk_[tid] < dirty.epoch) {
> clk_[tid] = dirty.epoch;
> @@ -299,10 +299,10 @@ void ThreadClock::ReleaseStore(ClockCache *c, SyncClock *dst) {
> dst->tab_idx_ = cached_idx_;
> dst->size_ = cached_size_;
> dst->blocks_ = cached_blocks_;
> - CHECK_EQ(dst->dirty_[0].tid, kInvalidTid);
> + CHECK_EQ(dst->dirty_[0].tid(), kInvalidTid);
> // The cached clock is shared (immutable),
> // so this is where we store the current clock.
> - dst->dirty_[0].tid = tid_;
> + dst->dirty_[0].set_tid(tid_);
> dst->dirty_[0].epoch = clk_[tid_];
> dst->release_store_tid_ = tid_;
> dst->release_store_reused_ = reused_;
> @@ -336,8 +336,7 @@ void ThreadClock::ReleaseStore(ClockCache *c, SyncClock *dst) {
> ce.reused = 0;
> i++;
> }
> - for (uptr i = 0; i < kDirtyTids; i++)
> - dst->dirty_[i].tid = kInvalidTid;
> + for (uptr i = 0; i < kDirtyTids; i++) dst->dirty_[i].set_tid(kInvalidTid);
> dst->release_store_tid_ = tid_;
> dst->release_store_reused_ = reused_;
> // Rememeber that we don't need to acquire it in future.
> @@ -369,10 +368,10 @@ void ThreadClock::UpdateCurrentThread(ClockCache *c, SyncClock *dst) const {
> // Update the threads time, but preserve 'acquired' flag.
> for (unsigned i = 0; i < kDirtyTids; i++) {
> SyncClock::Dirty *dirty = &dst->dirty_[i];
> - const unsigned tid = dirty->tid;
> + const unsigned tid = dirty->tid();
> if (tid == tid_ || tid == kInvalidTid) {
> CPP_STAT_INC(StatClockReleaseFast);
> - dirty->tid = tid_;
> + dirty->set_tid(tid_);
> dirty->epoch = clk_[tid_];
> return;
> }
> @@ -393,8 +392,8 @@ bool ThreadClock::IsAlreadyAcquired(const SyncClock *src) const {
> return false;
> for (unsigned i = 0; i < kDirtyTids; i++) {
> SyncClock::Dirty dirty = src->dirty_[i];
> - if (dirty.tid != kInvalidTid) {
> - if (clk_[dirty.tid] < dirty.epoch)
> + if (dirty.tid() != kInvalidTid) {
> + if (clk_[dirty.tid()] < dirty.epoch)
> return false;
> }
> }
> @@ -453,8 +452,7 @@ void SyncClock::ResetImpl() {
> blocks_ = 0;
> release_store_tid_ = kInvalidTid;
> release_store_reused_ = 0;
> - for (uptr i = 0; i < kDirtyTids; i++)
> - dirty_[i].tid = kInvalidTid;
> + for (uptr i = 0; i < kDirtyTids; i++) dirty_[i].set_tid(kInvalidTid);
> }
>
> void SyncClock::Resize(ClockCache *c, uptr nclk) {
> @@ -503,10 +501,10 @@ void SyncClock::Resize(ClockCache *c, uptr nclk) {
> void SyncClock::FlushDirty() {
> for (unsigned i = 0; i < kDirtyTids; i++) {
> Dirty *dirty = &dirty_[i];
> - if (dirty->tid != kInvalidTid) {
> - CHECK_LT(dirty->tid, size_);
> - elem(dirty->tid).epoch = dirty->epoch;
> - dirty->tid = kInvalidTid;
> + if (dirty->tid() != kInvalidTid) {
> + CHECK_LT(dirty->tid(), size_);
> + elem(dirty->tid()).epoch = dirty->epoch;
> + dirty->set_tid(kInvalidTid);
> }
> }
> }
> @@ -559,7 +557,7 @@ ALWAYS_INLINE bool SyncClock::Cachable() const {
> if (size_ == 0)
> return false;
> for (unsigned i = 0; i < kDirtyTids; i++) {
> - if (dirty_[i].tid != kInvalidTid)
> + if (dirty_[i].tid() != kInvalidTid)
> return false;
> }
> return atomic_load_relaxed(ref_ptr(tab_)) == 1;
> @@ -606,7 +604,7 @@ ALWAYS_INLINE void SyncClock::append_block(u32 idx) {
> u64 SyncClock::get(unsigned tid) const {
> for (unsigned i = 0; i < kDirtyTids; i++) {
> Dirty dirty = dirty_[i];
> - if (dirty.tid == tid)
> + if (dirty.tid() == tid)
> return dirty.epoch;
> }
> return elem(tid).epoch;
> @@ -625,9 +623,8 @@ void SyncClock::DebugDump(int(*printf)(const char *s, ...)) {
> for (uptr i = 0; i < size_; i++)
> printf("%s%llu", i == 0 ? "" : ",", elem(i).reused);
> printf("] release_store_tid=%d/%d dirty_tids=%d[%llu]/%d[%llu]",
> - release_store_tid_, release_store_reused_,
> - dirty_[0].tid, dirty_[0].epoch,
> - dirty_[1].tid, dirty_[1].epoch);
> + release_store_tid_, release_store_reused_, dirty_[0].tid(),
> + dirty_[0].epoch, dirty_[1].tid(), dirty_[1].epoch);
> }
>
> void SyncClock::Iter::Next() {
> diff --git a/libsanitizer/tsan/tsan_clock.h b/libsanitizer/tsan/tsan_clock.h
> index 736cdae06ba..31376a1bc9e 100644
> --- a/libsanitizer/tsan/tsan_clock.h
> +++ b/libsanitizer/tsan/tsan_clock.h
> @@ -17,7 +17,7 @@
>
> namespace __tsan {
>
> -typedef DenseSlabAlloc<ClockBlock, 1<<16, 1<<10> ClockAlloc;
> +typedef DenseSlabAlloc<ClockBlock, 1 << 22, 1 << 10> ClockAlloc;
> typedef DenseSlabAllocCache ClockCache;
>
> // The clock that lives in sync variables (mutexes, atomics, etc).
> @@ -65,10 +65,20 @@ class SyncClock {
> static const uptr kDirtyTids = 2;
>
> struct Dirty {
> - u64 epoch : kClkBits;
> - u64 tid : 64 - kClkBits; // kInvalidId if not active
> + u32 tid() const { return tid_ == kShortInvalidTid ? kInvalidTid : tid_; }
> + void set_tid(u32 tid) {
> + tid_ = tid == kInvalidTid ? kShortInvalidTid : tid;
> + }
> + u64 epoch : kClkBits;
> +
> + private:
> + // Full kInvalidTid won't fit into Dirty::tid.
> + static const u64 kShortInvalidTid = (1ull << (64 - kClkBits)) - 1;
> + u64 tid_ : 64 - kClkBits; // kInvalidId if not active
> };
>
> + static_assert(sizeof(Dirty) == 8, "Dirty is not 64bit");
> +
> unsigned release_store_tid_;
> unsigned release_store_reused_;
> Dirty dirty_[kDirtyTids];
> diff --git a/libsanitizer/tsan/tsan_defs.h b/libsanitizer/tsan/tsan_defs.h
> index 293d7deccc3..f53787aeba9 100644
> --- a/libsanitizer/tsan/tsan_defs.h
> +++ b/libsanitizer/tsan/tsan_defs.h
> @@ -98,8 +98,6 @@ const bool kCollectHistory = false;
> const bool kCollectHistory = true;
> #endif
>
> -const u16 kInvalidTid = kMaxTid + 1;
> -
> // The following "build consistency" machinery ensures that all source files
> // are built in the same configuration. Inconsistent builds lead to
> // hard to debug crashes.
> diff --git a/libsanitizer/tsan/tsan_dense_alloc.h b/libsanitizer/tsan/tsan_dense_alloc.h
> index 64fc50e95c2..6c89e405980 100644
> --- a/libsanitizer/tsan/tsan_dense_alloc.h
> +++ b/libsanitizer/tsan/tsan_dense_alloc.h
> @@ -29,28 +29,40 @@ class DenseSlabAllocCache {
> typedef u32 IndexT;
> uptr pos;
> IndexT cache[kSize];
> - template<typename T, uptr kL1Size, uptr kL2Size> friend class DenseSlabAlloc;
> + template <typename, uptr, uptr, u64>
> + friend class DenseSlabAlloc;
> };
>
> -template<typename T, uptr kL1Size, uptr kL2Size>
> +template <typename T, uptr kL1Size, uptr kL2Size, u64 kReserved = 0>
> class DenseSlabAlloc {
> public:
> typedef DenseSlabAllocCache Cache;
> typedef typename Cache::IndexT IndexT;
>
> - explicit DenseSlabAlloc(const char *name) {
> - // Check that kL1Size and kL2Size are sane.
> - CHECK_EQ(kL1Size & (kL1Size - 1), 0);
> - CHECK_EQ(kL2Size & (kL2Size - 1), 0);
> - CHECK_GE(1ull << (sizeof(IndexT) * 8), kL1Size * kL2Size);
> - // Check that it makes sense to use the dense alloc.
> - CHECK_GE(sizeof(T), sizeof(IndexT));
> - internal_memset(map_, 0, sizeof(map_));
> + static_assert((kL1Size & (kL1Size - 1)) == 0,
> + "kL1Size must be a power-of-two");
> + static_assert((kL2Size & (kL2Size - 1)) == 0,
> + "kL2Size must be a power-of-two");
> + static_assert((kL1Size * kL2Size) <= (1ull << (sizeof(IndexT) * 8)),
> + "kL1Size/kL2Size are too large");
> + static_assert(((kL1Size * kL2Size - 1) & kReserved) == 0,
> + "reserved bits don't fit");
> + static_assert(sizeof(T) > sizeof(IndexT),
> + "it doesn't make sense to use dense alloc");
> +
> + explicit DenseSlabAlloc(LinkerInitialized, const char *name) {
> freelist_ = 0;
> fillpos_ = 0;
> name_ = name;
> }
>
> + explicit DenseSlabAlloc(const char *name)
> + : DenseSlabAlloc(LINKER_INITIALIZED, name) {
> + // It can be very large.
> + // Don't page it in for linker initialized objects.
> + internal_memset(map_, 0, sizeof(map_));
> + }
> +
> ~DenseSlabAlloc() {
> for (uptr i = 0; i < kL1Size; i++) {
> if (map_[i] != 0)
> diff --git a/libsanitizer/tsan/tsan_external.cpp b/libsanitizer/tsan/tsan_external.cpp
> index 466b2bf0f66..a87e12f2936 100644
> --- a/libsanitizer/tsan/tsan_external.cpp
> +++ b/libsanitizer/tsan/tsan_external.cpp
> @@ -111,12 +111,12 @@ void __tsan_external_assign_tag(void *addr, void *tag) {
>
> SANITIZER_INTERFACE_ATTRIBUTE
> void __tsan_external_read(void *addr, void *caller_pc, void *tag) {
> - ExternalAccess(addr, STRIP_PC(caller_pc), tag, MemoryRead);
> + ExternalAccess(addr, STRIP_PAC_PC(caller_pc), tag, MemoryRead);
> }
>
> SANITIZER_INTERFACE_ATTRIBUTE
> void __tsan_external_write(void *addr, void *caller_pc, void *tag) {
> - ExternalAccess(addr, STRIP_PC(caller_pc), tag, MemoryWrite);
> + ExternalAccess(addr, STRIP_PAC_PC(caller_pc), tag, MemoryWrite);
> }
> } // extern "C"
>
> diff --git a/libsanitizer/tsan/tsan_interceptors_mac.cpp b/libsanitizer/tsan/tsan_interceptors_mac.cpp
> index aa29536d861..ed10fccc980 100644
> --- a/libsanitizer/tsan/tsan_interceptors_mac.cpp
> +++ b/libsanitizer/tsan/tsan_interceptors_mac.cpp
> @@ -438,6 +438,7 @@ struct fake_shared_weak_count {
> virtual void on_zero_shared() = 0;
> virtual void _unused_0x18() = 0;
> virtual void on_zero_shared_weak() = 0;
> + virtual ~fake_shared_weak_count() = 0; // suppress -Wnon-virtual-dtor
> };
> } // namespace
>
> diff --git a/libsanitizer/tsan/tsan_interceptors_posix.cpp b/libsanitizer/tsan/tsan_interceptors_posix.cpp
> index aa04d8dfb67..2651e22c39f 100644
> --- a/libsanitizer/tsan/tsan_interceptors_posix.cpp
> +++ b/libsanitizer/tsan/tsan_interceptors_posix.cpp
> @@ -54,10 +54,6 @@ using namespace __tsan;
> #define vfork __vfork14
> #endif
>
> -#if SANITIZER_ANDROID
> -#define mallopt(a, b)
> -#endif
> -
> #ifdef __mips__
> const int kSigCount = 129;
> #else
> @@ -85,6 +81,8 @@ extern "C" int pthread_attr_init(void *attr);
> extern "C" int pthread_attr_destroy(void *attr);
> DECLARE_REAL(int, pthread_attr_getdetachstate, void *, void *)
> extern "C" int pthread_attr_setstacksize(void *attr, uptr stacksize);
> +extern "C" int pthread_atfork(void (*prepare)(void), void (*parent)(void),
> + void (*child)(void));
> extern "C" int pthread_key_create(unsigned *key, void (*destructor)(void* v));
> extern "C" int pthread_setspecific(unsigned key, const void *v);
> DECLARE_REAL(int, pthread_mutexattr_gettype, void *, void *)
> @@ -97,7 +95,7 @@ extern "C" void _exit(int status);
> extern "C" int fileno_unlocked(void *stream);
> extern "C" int dirfd(void *dirp);
> #endif
> -#if !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_NETBSD
> +#if SANITIZER_GLIBC
> extern "C" int mallopt(int param, int value);
> #endif
> #if SANITIZER_NETBSD
> @@ -659,8 +657,11 @@ TSAN_INTERCEPTOR(void*, malloc, uptr size) {
> return p;
> }
>
> +// In glibc<2.25, dynamic TLS blocks are allocated by __libc_memalign. Intercept
> +// __libc_memalign so that (1) we can detect races (2) free will not be called
> +// on libc internally allocated blocks.
> TSAN_INTERCEPTOR(void*, __libc_memalign, uptr align, uptr sz) {
> - SCOPED_TSAN_INTERCEPTOR(__libc_memalign, align, sz);
> + SCOPED_INTERCEPTOR_RAW(__libc_memalign, align, sz);
> return user_memalign(thr, pc, align, sz);
> }
>
> @@ -773,6 +774,11 @@ static void *mmap_interceptor(ThreadState *thr, uptr pc, Mmap real_mmap,
> if (!fix_mmap_addr(&addr, sz, flags)) return MAP_FAILED;
> void *res = real_mmap(addr, sz, prot, flags, fd, off);
> if (res != MAP_FAILED) {
> + if (!IsAppMem((uptr)res) || !IsAppMem((uptr)res + sz - 1)) {
> + Report("ThreadSanitizer: mmap at bad address: addr=%p size=%p res=%p\n",
> + addr, (void*)sz, res);
> + Die();
> + }
> if (fd > 0) FdAccess(thr, pc, fd);
> MemoryRangeImitateWriteOrResetRange(thr, pc, (uptr)res, sz);
> }
> @@ -1122,27 +1128,37 @@ static void *init_cond(void *c, bool force = false) {
> return (void*)cond;
> }
>
> +namespace {
> +
> +template <class Fn>
> struct CondMutexUnlockCtx {
> ScopedInterceptor *si;
> ThreadState *thr;
> uptr pc;
> void *m;
> + void *c;
> + const Fn &fn;
> +
> + int Cancel() const { return fn(); }
> + void Unlock() const;
> };
>
> -static void cond_mutex_unlock(CondMutexUnlockCtx *arg) {
> +template <class Fn>
> +void CondMutexUnlockCtx<Fn>::Unlock() const {
> // pthread_cond_wait interceptor has enabled async signal delivery
> // (see BlockingCall below). Disable async signals since we are running
> // tsan code. Also ScopedInterceptor and BlockingCall destructors won't run
> // since the thread is cancelled, so we have to manually execute them
> // (the thread still can run some user code due to pthread_cleanup_push).
> - ThreadSignalContext *ctx = SigCtx(arg->thr);
> + ThreadSignalContext *ctx = SigCtx(thr);
> CHECK_EQ(atomic_load(&ctx->in_blocking_func, memory_order_relaxed), 1);
> atomic_store(&ctx->in_blocking_func, 0, memory_order_relaxed);
> - MutexPostLock(arg->thr, arg->pc, (uptr)arg->m, MutexFlagDoPreLockOnPostLock);
> + MutexPostLock(thr, pc, (uptr)m, MutexFlagDoPreLockOnPostLock);
> // Undo BlockingCall ctor effects.
> - arg->thr->ignore_interceptors--;
> - arg->si->~ScopedInterceptor();
> + thr->ignore_interceptors--;
> + si->~ScopedInterceptor();
> }
> +} // namespace
>
> INTERCEPTOR(int, pthread_cond_init, void *c, void *a) {
> void *cond = init_cond(c, true);
> @@ -1151,20 +1167,24 @@ INTERCEPTOR(int, pthread_cond_init, void *c, void *a) {
> return REAL(pthread_cond_init)(cond, a);
> }
>
> -static int cond_wait(ThreadState *thr, uptr pc, ScopedInterceptor *si,
> - int (*fn)(void *c, void *m, void *abstime), void *c,
> - void *m, void *t) {
> +template <class Fn>
> +int cond_wait(ThreadState *thr, uptr pc, ScopedInterceptor *si, const Fn &fn,
> + void *c, void *m) {
> MemoryAccessRange(thr, pc, (uptr)c, sizeof(uptr), false);
> MutexUnlock(thr, pc, (uptr)m);
> - CondMutexUnlockCtx arg = {si, thr, pc, m};
> int res = 0;
> // This ensures that we handle mutex lock even in case of pthread_cancel.
> // See test/tsan/cond_cancel.cpp.
> {
> // Enable signal delivery while the thread is blocked.
> BlockingCall bc(thr);
> + CondMutexUnlockCtx<Fn> arg = {si, thr, pc, m, c, fn};
> res = call_pthread_cancel_with_cleanup(
> - fn, c, m, t, (void (*)(void *arg))cond_mutex_unlock, &arg);
> + [](void *arg) -> int {
> + return ((const CondMutexUnlockCtx<Fn> *)arg)->Cancel();
> + },
> + [](void *arg) { ((const CondMutexUnlockCtx<Fn> *)arg)->Unlock(); },
> + &arg);
> }
> if (res == errno_EOWNERDEAD) MutexRepair(thr, pc, (uptr)m);
> MutexPostLock(thr, pc, (uptr)m, MutexFlagDoPreLockOnPostLock);
> @@ -1174,25 +1194,46 @@ static int cond_wait(ThreadState *thr, uptr pc, ScopedInterceptor *si,
> INTERCEPTOR(int, pthread_cond_wait, void *c, void *m) {
> void *cond = init_cond(c);
> SCOPED_TSAN_INTERCEPTOR(pthread_cond_wait, cond, m);
> - return cond_wait(thr, pc, &si, (int (*)(void *c, void *m, void *abstime))REAL(
> - pthread_cond_wait),
> - cond, m, 0);
> + return cond_wait(
> + thr, pc, &si, [=]() { return REAL(pthread_cond_wait)(cond, m); }, cond,
> + m);
> }
>
> INTERCEPTOR(int, pthread_cond_timedwait, void *c, void *m, void *abstime) {
> void *cond = init_cond(c);
> SCOPED_TSAN_INTERCEPTOR(pthread_cond_timedwait, cond, m, abstime);
> - return cond_wait(thr, pc, &si, REAL(pthread_cond_timedwait), cond, m,
> - abstime);
> + return cond_wait(
> + thr, pc, &si,
> + [=]() { return REAL(pthread_cond_timedwait)(cond, m, abstime); }, cond,
> + m);
> }
>
> +#if SANITIZER_LINUX
> +INTERCEPTOR(int, pthread_cond_clockwait, void *c, void *m,
> + __sanitizer_clockid_t clock, void *abstime) {
> + void *cond = init_cond(c);
> + SCOPED_TSAN_INTERCEPTOR(pthread_cond_clockwait, cond, m, clock, abstime);
> + return cond_wait(
> + thr, pc, &si,
> + [=]() { return REAL(pthread_cond_clockwait)(cond, m, clock, abstime); },
> + cond, m);
> +}
> +#define TSAN_MAYBE_PTHREAD_COND_CLOCKWAIT TSAN_INTERCEPT(pthread_cond_clockwait)
> +#else
> +#define TSAN_MAYBE_PTHREAD_COND_CLOCKWAIT
> +#endif
> +
> #if SANITIZER_MAC
> INTERCEPTOR(int, pthread_cond_timedwait_relative_np, void *c, void *m,
> void *reltime) {
> void *cond = init_cond(c);
> SCOPED_TSAN_INTERCEPTOR(pthread_cond_timedwait_relative_np, cond, m, reltime);
> - return cond_wait(thr, pc, &si, REAL(pthread_cond_timedwait_relative_np), cond,
> - m, reltime);
> + return cond_wait(
> + thr, pc, &si,
> + [=]() {
> + return REAL(pthread_cond_timedwait_relative_np)(cond, m, reltime);
> + },
> + cond, m);
> }
> #endif
>
> @@ -1937,7 +1978,8 @@ static void CallUserSignalHandler(ThreadState *thr, bool sync, bool acquire,
> // because in async signal processing case (when handler is called directly
> // from rtl_generic_sighandler) we have not yet received the reraised
> // signal; and it looks too fragile to intercept all ways to reraise a signal.
> - if (flags()->report_bugs && !sync && sig != SIGTERM && errno != 99) {
> + if (ShouldReport(thr, ReportTypeErrnoInSignal) && !sync && sig != SIGTERM &&
> + errno != 99) {
> VarSizeStackTrace stack;
> // StackTrace::GetNestInstructionPc(pc) is used because return address is
> // expected, OutputReport() will undo this.
> @@ -2107,26 +2149,32 @@ TSAN_INTERCEPTOR(int, fork, int fake) {
> if (in_symbolizer())
> return REAL(fork)(fake);
> SCOPED_INTERCEPTOR_RAW(fork, fake);
> + return REAL(fork)(fake);
> +}
> +
> +void atfork_prepare() {
> + if (in_symbolizer())
> + return;
> + ThreadState *thr = cur_thread();
> + const uptr pc = StackTrace::GetCurrentPc();
> ForkBefore(thr, pc);
> - int pid;
> - {
> - // On OS X, REAL(fork) can call intercepted functions (OSSpinLockLock), and
> - // we'll assert in CheckNoLocks() unless we ignore interceptors.
> - ScopedIgnoreInterceptors ignore;
> - pid = REAL(fork)(fake);
> - }
> - if (pid == 0) {
> - // child
> - ForkChildAfter(thr, pc);
> - FdOnFork(thr, pc);
> - } else if (pid > 0) {
> - // parent
> - ForkParentAfter(thr, pc);
> - } else {
> - // error
> - ForkParentAfter(thr, pc);
> - }
> - return pid;
> +}
> +
> +void atfork_parent() {
> + if (in_symbolizer())
> + return;
> + ThreadState *thr = cur_thread();
> + const uptr pc = StackTrace::GetCurrentPc();
> + ForkParentAfter(thr, pc);
> +}
> +
> +void atfork_child() {
> + if (in_symbolizer())
> + return;
> + ThreadState *thr = cur_thread();
> + const uptr pc = StackTrace::GetCurrentPc();
> + ForkChildAfter(thr, pc);
> + FdOnFork(thr, pc);
> }
>
> TSAN_INTERCEPTOR(int, vfork, int fake) {
> @@ -2479,13 +2527,10 @@ static USED void syscall_fd_release(uptr pc, int fd) {
> FdRelease(thr, pc, fd);
> }
>
> -static void syscall_pre_fork(uptr pc) {
> - TSAN_SYSCALL();
> - ForkBefore(thr, pc);
> -}
> +static void syscall_pre_fork(uptr pc) { ForkBefore(cur_thread(), pc); }
>
> static void syscall_post_fork(uptr pc, int pid) {
> - TSAN_SYSCALL();
> + ThreadState *thr = cur_thread();
> if (pid == 0) {
> // child
> ForkChildAfter(thr, pc);
> @@ -2635,7 +2680,7 @@ void InitializeInterceptors() {
> #endif
>
> // Instruct libc malloc to consume less memory.
> -#if SANITIZER_LINUX
> +#if SANITIZER_GLIBC
> mallopt(1, 0); // M_MXFAST
> mallopt(-3, 32*1024); // M_MMAP_THRESHOLD
> #endif
> @@ -2698,6 +2743,8 @@ void InitializeInterceptors() {
> TSAN_INTERCEPT_VER(pthread_cond_timedwait, PTHREAD_ABI_BASE);
> TSAN_INTERCEPT_VER(pthread_cond_destroy, PTHREAD_ABI_BASE);
>
> + TSAN_MAYBE_PTHREAD_COND_CLOCKWAIT;
> +
> TSAN_INTERCEPT(pthread_mutex_init);
> TSAN_INTERCEPT(pthread_mutex_destroy);
> TSAN_INTERCEPT(pthread_mutex_trylock);
> @@ -2799,6 +2846,10 @@ void InitializeInterceptors() {
> Printf("ThreadSanitizer: failed to setup atexit callback\n");
> Die();
> }
> + if (pthread_atfork(atfork_prepare, atfork_parent, atfork_child)) {
> + Printf("ThreadSanitizer: failed to setup atfork callbacks\n");
> + Die();
> + }
>
> #if !SANITIZER_MAC && !SANITIZER_NETBSD && !SANITIZER_FREEBSD
> if (pthread_key_create(&interceptor_ctx()->finalize_key, &thread_finalize)) {
> diff --git a/libsanitizer/tsan/tsan_interface.cpp b/libsanitizer/tsan/tsan_interface.cpp
> index 55f1c9834f7..9bd0e8580b1 100644
> --- a/libsanitizer/tsan/tsan_interface.cpp
> +++ b/libsanitizer/tsan/tsan_interface.cpp
> @@ -40,13 +40,13 @@ void __tsan_write16(void *addr) {
> }
>
> void __tsan_read16_pc(void *addr, void *pc) {
> - MemoryRead(cur_thread(), STRIP_PC(pc), (uptr)addr, kSizeLog8);
> - MemoryRead(cur_thread(), STRIP_PC(pc), (uptr)addr + 8, kSizeLog8);
> + MemoryRead(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, kSizeLog8);
> + MemoryRead(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr + 8, kSizeLog8);
> }
>
> void __tsan_write16_pc(void *addr, void *pc) {
> - MemoryWrite(cur_thread(), STRIP_PC(pc), (uptr)addr, kSizeLog8);
> - MemoryWrite(cur_thread(), STRIP_PC(pc), (uptr)addr + 8, kSizeLog8);
> + MemoryWrite(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, kSizeLog8);
> + MemoryWrite(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr + 8, kSizeLog8);
> }
>
> // __tsan_unaligned_read/write calls are emitted by compiler.
> diff --git a/libsanitizer/tsan/tsan_interface.h b/libsanitizer/tsan/tsan_interface.h
> index 6d7286ca5b8..6e022b56850 100644
> --- a/libsanitizer/tsan/tsan_interface.h
> +++ b/libsanitizer/tsan/tsan_interface.h
> @@ -204,7 +204,7 @@ __extension__ typedef __int128 a128;
> #endif
>
> // Part of ABI, do not change.
> -// https://github.com/llvm/llvm-project/blob/master/libcxx/include/atomic
> +// https://github.com/llvm/llvm-project/blob/main/libcxx/include/atomic
> typedef enum {
> mo_relaxed,
> mo_consume,
> @@ -415,6 +415,13 @@ void __tsan_go_atomic32_compare_exchange(ThreadState *thr, uptr cpc, uptr pc,
> SANITIZER_INTERFACE_ATTRIBUTE
> void __tsan_go_atomic64_compare_exchange(ThreadState *thr, uptr cpc, uptr pc,
> u8 *a);
> +
> +SANITIZER_INTERFACE_ATTRIBUTE
> +void __tsan_on_initialize();
> +
> +SANITIZER_INTERFACE_ATTRIBUTE
> +int __tsan_on_finalize(int failed);
> +
> } // extern "C"
>
> } // namespace __tsan
> diff --git a/libsanitizer/tsan/tsan_interface_inl.h b/libsanitizer/tsan/tsan_interface_inl.h
> index f5d743c1077..5e77d4d3d28 100644
> --- a/libsanitizer/tsan/tsan_interface_inl.h
> +++ b/libsanitizer/tsan/tsan_interface_inl.h
> @@ -51,35 +51,35 @@ void __tsan_write8(void *addr) {
> }
>
> void __tsan_read1_pc(void *addr, void *pc) {
> - MemoryRead(cur_thread(), STRIP_PC(pc), (uptr)addr, kSizeLog1);
> + MemoryRead(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, kSizeLog1);
> }
>
> void __tsan_read2_pc(void *addr, void *pc) {
> - MemoryRead(cur_thread(), STRIP_PC(pc), (uptr)addr, kSizeLog2);
> + MemoryRead(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, kSizeLog2);
> }
>
> void __tsan_read4_pc(void *addr, void *pc) {
> - MemoryRead(cur_thread(), STRIP_PC(pc), (uptr)addr, kSizeLog4);
> + MemoryRead(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, kSizeLog4);
> }
>
> void __tsan_read8_pc(void *addr, void *pc) {
> - MemoryRead(cur_thread(), STRIP_PC(pc), (uptr)addr, kSizeLog8);
> + MemoryRead(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, kSizeLog8);
> }
>
> void __tsan_write1_pc(void *addr, void *pc) {
> - MemoryWrite(cur_thread(), STRIP_PC(pc), (uptr)addr, kSizeLog1);
> + MemoryWrite(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, kSizeLog1);
> }
>
> void __tsan_write2_pc(void *addr, void *pc) {
> - MemoryWrite(cur_thread(), STRIP_PC(pc), (uptr)addr, kSizeLog2);
> + MemoryWrite(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, kSizeLog2);
> }
>
> void __tsan_write4_pc(void *addr, void *pc) {
> - MemoryWrite(cur_thread(), STRIP_PC(pc), (uptr)addr, kSizeLog4);
> + MemoryWrite(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, kSizeLog4);
> }
>
> void __tsan_write8_pc(void *addr, void *pc) {
> - MemoryWrite(cur_thread(), STRIP_PC(pc), (uptr)addr, kSizeLog8);
> + MemoryWrite(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, kSizeLog8);
> }
>
> void __tsan_vptr_update(void **vptr_p, void *new_val) {
> @@ -101,7 +101,7 @@ void __tsan_vptr_read(void **vptr_p) {
> }
>
> void __tsan_func_entry(void *pc) {
> - FuncEntry(cur_thread(), STRIP_PC(pc));
> + FuncEntry(cur_thread(), STRIP_PAC_PC(pc));
> }
>
> void __tsan_func_exit() {
> @@ -125,9 +125,9 @@ void __tsan_write_range(void *addr, uptr size) {
> }
>
> void __tsan_read_range_pc(void *addr, uptr size, void *pc) {
> - MemoryAccessRange(cur_thread(), STRIP_PC(pc), (uptr)addr, size, false);
> + MemoryAccessRange(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, size, false);
> }
>
> void __tsan_write_range_pc(void *addr, uptr size, void *pc) {
> - MemoryAccessRange(cur_thread(), STRIP_PC(pc), (uptr)addr, size, true);
> + MemoryAccessRange(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, size, true);
> }
> diff --git a/libsanitizer/tsan/tsan_mman.cpp b/libsanitizer/tsan/tsan_mman.cpp
> index 743e67bf2f7..45a39f0f8ec 100644
> --- a/libsanitizer/tsan/tsan_mman.cpp
> +++ b/libsanitizer/tsan/tsan_mman.cpp
> @@ -145,7 +145,7 @@ void AllocatorPrintStats() {
>
> static void SignalUnsafeCall(ThreadState *thr, uptr pc) {
> if (atomic_load_relaxed(&thr->in_signal_handler) == 0 ||
> - !flags()->report_signal_unsafe)
> + !ShouldReport(thr, ReportTypeSignalUnsafe))
> return;
> VarSizeStackTrace stack;
> ObtainCurrentStack(thr, pc, &stack);
> diff --git a/libsanitizer/tsan/tsan_platform.h b/libsanitizer/tsan/tsan_platform.h
> index 16169cab666..101522d8fa4 100644
> --- a/libsanitizer/tsan/tsan_platform.h
> +++ b/libsanitizer/tsan/tsan_platform.h
> @@ -23,9 +23,21 @@
>
> namespace __tsan {
>
> +#if defined(__x86_64__)
> +#define HAS_48_BIT_ADDRESS_SPACE 1
> +#elif SANITIZER_IOSSIM // arm64 iOS simulators (order of #if matters)
> +#define HAS_48_BIT_ADDRESS_SPACE 1
> +#elif SANITIZER_IOS // arm64 iOS devices (order of #if matters)
> +#define HAS_48_BIT_ADDRESS_SPACE 0
> +#elif SANITIZER_MAC // arm64 macOS (order of #if matters)
> +#define HAS_48_BIT_ADDRESS_SPACE 1
> +#else
> +#define HAS_48_BIT_ADDRESS_SPACE 0
> +#endif
> +
> #if !SANITIZER_GO
>
> -#if defined(__x86_64__)
> +#if HAS_48_BIT_ADDRESS_SPACE
> /*
> C/C++ on linux/x86_64 and freebsd/x86_64
> 0000 0000 1000 - 0080 0000 0000: main binary and/or MAP_32BIT mappings (512GB)
> @@ -93,7 +105,7 @@ fe00 0000 00 - ff00 0000 00: heap (4 GB)
> ff00 0000 00 - ff80 0000 00: - (2 GB)
> ff80 0000 00 - ffff ffff ff: modules and main thread stack (<2 GB)
> */
> -struct Mapping {
> +struct Mapping40 {
> static const uptr kMetaShadowBeg = 0x4000000000ull;
> static const uptr kMetaShadowEnd = 0x5000000000ull;
> static const uptr kTraceMemBeg = 0xb000000000ull;
> @@ -114,6 +126,7 @@ struct Mapping {
> };
>
> #define TSAN_MID_APP_RANGE 1
> +#define TSAN_RUNTIME_VMA 1
> #elif defined(__aarch64__) && defined(__APPLE__)
> /*
> C/C++ on Darwin/iOS/ARM64 (36-bit VMA, 64 GB VM)
> @@ -146,7 +159,7 @@ struct Mapping {
> static const uptr kVdsoBeg = 0x7000000000000000ull;
> };
>
> -#elif defined(__aarch64__)
> +#elif defined(__aarch64__) && !defined(__APPLE__)
> // AArch64 supports multiple VMA which leads to multiple address transformation
> // functions. To support these multiple VMAS transformations and mappings TSAN
> // runtime for AArch64 uses an external memory read (vmaSize) to select which
> @@ -354,7 +367,7 @@ struct Mapping47 {
> #define TSAN_RUNTIME_VMA 1
> #endif
>
> -#elif SANITIZER_GO && !SANITIZER_WINDOWS && defined(__x86_64__)
> +#elif SANITIZER_GO && !SANITIZER_WINDOWS && HAS_48_BIT_ADDRESS_SPACE
>
> /* Go on linux, darwin and freebsd on x86_64
> 0000 0000 1000 - 0000 1000 0000: executable
> @@ -502,7 +515,7 @@ Go on linux/mips64 (47-bit VMA)
> 6000 0000 0000 - 6200 0000 0000: traces
> 6200 0000 0000 - 8000 0000 0000: -
> */
> -struct Mapping {
> +struct Mapping47 {
> static const uptr kMetaShadowBeg = 0x300000000000ull;
> static const uptr kMetaShadowEnd = 0x400000000000ull;
> static const uptr kTraceMemBeg = 0x600000000000ull;
> @@ -512,6 +525,9 @@ struct Mapping {
> static const uptr kAppMemBeg = 0x000000001000ull;
> static const uptr kAppMemEnd = 0x00e000000000ull;
> };
> +
> +#define TSAN_RUNTIME_VMA 1
> +
> #else
> # error "Unknown platform"
> #endif
> @@ -592,6 +608,16 @@ uptr MappingArchImpl(void) {
> }
> DCHECK(0);
> return 0;
> +#elif defined(__mips64)
> + switch (vmaSize) {
> +#if !SANITIZER_GO
> + case 40: return MappingImpl<Mapping40, Type>();
> +#else
> + case 47: return MappingImpl<Mapping47, Type>();
> +#endif
> + }
> + DCHECK(0);
> + return 0;
> #else
> return MappingImpl<Mapping, Type>();
> #endif
> @@ -749,6 +775,16 @@ bool IsAppMem(uptr mem) {
> }
> DCHECK(0);
> return false;
> +#elif defined(__mips64)
> + switch (vmaSize) {
> +#if !SANITIZER_GO
> + case 40: return IsAppMemImpl<Mapping40>(mem);
> +#else
> + case 47: return IsAppMemImpl<Mapping47>(mem);
> +#endif
> + }
> + DCHECK(0);
> + return false;
> #else
> return IsAppMemImpl<Mapping>(mem);
> #endif
> @@ -780,6 +816,16 @@ bool IsShadowMem(uptr mem) {
> }
> DCHECK(0);
> return false;
> +#elif defined(__mips64)
> + switch (vmaSize) {
> +#if !SANITIZER_GO
> + case 40: return IsShadowMemImpl<Mapping40>(mem);
> +#else
> + case 47: return IsShadowMemImpl<Mapping47>(mem);
> +#endif
> + }
> + DCHECK(0);
> + return false;
> #else
> return IsShadowMemImpl<Mapping>(mem);
> #endif
> @@ -811,6 +857,16 @@ bool IsMetaMem(uptr mem) {
> }
> DCHECK(0);
> return false;
> +#elif defined(__mips64)
> + switch (vmaSize) {
> +#if !SANITIZER_GO
> + case 40: return IsMetaMemImpl<Mapping40>(mem);
> +#else
> + case 47: return IsMetaMemImpl<Mapping47>(mem);
> +#endif
> + }
> + DCHECK(0);
> + return false;
> #else
> return IsMetaMemImpl<Mapping>(mem);
> #endif
> @@ -852,6 +908,16 @@ uptr MemToShadow(uptr x) {
> }
> DCHECK(0);
> return 0;
> +#elif defined(__mips64)
> + switch (vmaSize) {
> +#if !SANITIZER_GO
> + case 40: return MemToShadowImpl<Mapping40>(x);
> +#else
> + case 47: return MemToShadowImpl<Mapping47>(x);
> +#endif
> + }
> + DCHECK(0);
> + return 0;
> #else
> return MemToShadowImpl<Mapping>(x);
> #endif
> @@ -895,6 +961,16 @@ u32 *MemToMeta(uptr x) {
> }
> DCHECK(0);
> return 0;
> +#elif defined(__mips64)
> + switch (vmaSize) {
> +#if !SANITIZER_GO
> + case 40: return MemToMetaImpl<Mapping40>(x);
> +#else
> + case 47: return MemToMetaImpl<Mapping47>(x);
> +#endif
> + }
> + DCHECK(0);
> + return 0;
> #else
> return MemToMetaImpl<Mapping>(x);
> #endif
> @@ -951,6 +1027,16 @@ uptr ShadowToMem(uptr s) {
> }
> DCHECK(0);
> return 0;
> +#elif defined(__mips64)
> + switch (vmaSize) {
> +#if !SANITIZER_GO
> + case 40: return ShadowToMemImpl<Mapping40>(s);
> +#else
> + case 47: return ShadowToMemImpl<Mapping47>(s);
> +#endif
> + }
> + DCHECK(0);
> + return 0;
> #else
> return ShadowToMemImpl<Mapping>(s);
> #endif
> @@ -990,6 +1076,16 @@ uptr GetThreadTrace(int tid) {
> }
> DCHECK(0);
> return 0;
> +#elif defined(__mips64)
> + switch (vmaSize) {
> +#if !SANITIZER_GO
> + case 40: return GetThreadTraceImpl<Mapping40>(tid);
> +#else
> + case 47: return GetThreadTraceImpl<Mapping47>(tid);
> +#endif
> + }
> + DCHECK(0);
> + return 0;
> #else
> return GetThreadTraceImpl<Mapping>(tid);
> #endif
> @@ -1024,6 +1120,16 @@ uptr GetThreadTraceHeader(int tid) {
> }
> DCHECK(0);
> return 0;
> +#elif defined(__mips64)
> + switch (vmaSize) {
> +#if !SANITIZER_GO
> + case 40: return GetThreadTraceHeaderImpl<Mapping40>(tid);
> +#else
> + case 47: return GetThreadTraceHeaderImpl<Mapping47>(tid);
> +#endif
> + }
> + DCHECK(0);
> + return 0;
> #else
> return GetThreadTraceHeaderImpl<Mapping>(tid);
> #endif
> @@ -1040,9 +1146,8 @@ int ExtractRecvmsgFDs(void *msg, int *fds, int nfd);
> uptr ExtractLongJmpSp(uptr *env);
> void ImitateTlsWrite(ThreadState *thr, uptr tls_addr, uptr tls_size);
>
> -int call_pthread_cancel_with_cleanup(int(*fn)(void *c, void *m,
> - void *abstime), void *c, void *m, void *abstime,
> - void(*cleanup)(void *arg), void *arg);
> +int call_pthread_cancel_with_cleanup(int (*fn)(void *arg),
> + void (*cleanup)(void *arg), void *arg);
>
> void DestroyThreadState();
> void PlatformCleanUpThreadState(ThreadState *thr);
> diff --git a/libsanitizer/tsan/tsan_platform_linux.cpp b/libsanitizer/tsan/tsan_platform_linux.cpp
> index d136dcb1cec..e5b6690edfd 100644
> --- a/libsanitizer/tsan/tsan_platform_linux.cpp
> +++ b/libsanitizer/tsan/tsan_platform_linux.cpp
> @@ -250,6 +250,20 @@ void InitializePlatformEarly() {
> Die();
> }
> # endif
> +#elif defined(__mips64)
> +# if !SANITIZER_GO
> + if (vmaSize != 40) {
> + Printf("FATAL: ThreadSanitizer: unsupported VMA range\n");
> + Printf("FATAL: Found %zd - Supported 40\n", vmaSize);
> + Die();
> + }
> +# else
> + if (vmaSize != 47) {
> + Printf("FATAL: ThreadSanitizer: unsupported VMA range\n");
> + Printf("FATAL: Found %zd - Supported 47\n", vmaSize);
> + Die();
> + }
> +# endif
> #endif
> #endif
> }
> @@ -443,14 +457,13 @@ void ImitateTlsWrite(ThreadState *thr, uptr tls_addr, uptr tls_size) {
>
> // Note: this function runs with async signals enabled,
> // so it must not touch any tsan state.
> -int call_pthread_cancel_with_cleanup(int(*fn)(void *c, void *m,
> - void *abstime), void *c, void *m, void *abstime,
> - void(*cleanup)(void *arg), void *arg) {
> +int call_pthread_cancel_with_cleanup(int (*fn)(void *arg),
> + void (*cleanup)(void *arg), void *arg) {
> // pthread_cleanup_push/pop are hardcore macros mess.
> // We can't intercept nor call them w/o including pthread.h.
> int res;
> pthread_cleanup_push(cleanup, arg);
> - res = fn(c, m, abstime);
> + res = fn(arg);
> pthread_cleanup_pop(0);
> return res;
> }
> @@ -484,7 +497,7 @@ ThreadState *cur_thread() {
> dead_thread_state->fast_state.SetIgnoreBit();
> dead_thread_state->ignore_interceptors = 1;
> dead_thread_state->is_dead = true;
> - *const_cast<int*>(&dead_thread_state->tid) = -1;
> + *const_cast<u32*>(&dead_thread_state->tid) = -1;
> CHECK_EQ(0, internal_mprotect(dead_thread_state, sizeof(ThreadState),
> PROT_READ));
> }
> diff --git a/libsanitizer/tsan/tsan_platform_mac.cpp b/libsanitizer/tsan/tsan_platform_mac.cpp
> index ec2c5fb1621..d9719a136b2 100644
> --- a/libsanitizer/tsan/tsan_platform_mac.cpp
> +++ b/libsanitizer/tsan/tsan_platform_mac.cpp
> @@ -234,7 +234,7 @@ static void my_pthread_introspection_hook(unsigned int event, pthread_t thread,
> #endif
>
> void InitializePlatformEarly() {
> -#if !SANITIZER_GO && defined(__aarch64__)
> +#if !SANITIZER_GO && !HAS_48_BIT_ADDRESS_SPACE
> uptr max_vm = GetMaxUserVirtualAddress() + 1;
> if (max_vm != Mapping::kHiAppMemEnd) {
> Printf("ThreadSanitizer: unsupported vm address limit %p, expected %p.\n",
> @@ -306,14 +306,13 @@ void ImitateTlsWrite(ThreadState *thr, uptr tls_addr, uptr tls_size) {
> #if !SANITIZER_GO
> // Note: this function runs with async signals enabled,
> // so it must not touch any tsan state.
> -int call_pthread_cancel_with_cleanup(int(*fn)(void *c, void *m,
> - void *abstime), void *c, void *m, void *abstime,
> - void(*cleanup)(void *arg), void *arg) {
> +int call_pthread_cancel_with_cleanup(int (*fn)(void *arg),
> + void (*cleanup)(void *arg), void *arg) {
> // pthread_cleanup_push/pop are hardcore macros mess.
> // We can't intercept nor call them w/o including pthread.h.
> int res;
> pthread_cleanup_push(cleanup, arg);
> - res = fn(c, m, abstime);
> + res = fn(arg);
> pthread_cleanup_pop(0);
> return res;
> }
> diff --git a/libsanitizer/tsan/tsan_platform_posix.cpp b/libsanitizer/tsan/tsan_platform_posix.cpp
> index d56b6c3b9c5..73e1d4577c2 100644
> --- a/libsanitizer/tsan/tsan_platform_posix.cpp
> +++ b/libsanitizer/tsan/tsan_platform_posix.cpp
> @@ -99,7 +99,7 @@ void CheckAndProtect() {
> Die();
> }
>
> -#if defined(__aarch64__) && defined(__APPLE__)
> +#if defined(__aarch64__) && defined(__APPLE__) && !HAS_48_BIT_ADDRESS_SPACE
> ProtectRange(HeapMemEnd(), ShadowBeg());
> ProtectRange(ShadowEnd(), MetaShadowBeg());
> ProtectRange(MetaShadowEnd(), TraceMemBeg());
> diff --git a/libsanitizer/tsan/tsan_report.cpp b/libsanitizer/tsan/tsan_report.cpp
> index 968c7b97553..8ef9f0cd4fe 100644
> --- a/libsanitizer/tsan/tsan_report.cpp
> +++ b/libsanitizer/tsan/tsan_report.cpp
> @@ -69,7 +69,7 @@ ReportDesc::~ReportDesc() {
>
> const int kThreadBufSize = 32;
> const char *thread_name(char *buf, int tid) {
> - if (tid == 0)
> + if (tid == kMainTid)
> return "main thread";
> internal_snprintf(buf, kThreadBufSize, "thread T%d", tid);
> return buf;
> @@ -127,7 +127,7 @@ void PrintStack(const ReportStack *ent) {
> }
> SymbolizedStack *frame = ent->frames;
> for (int i = 0; frame && frame->info.address; frame = frame->next, i++) {
> - InternalScopedString res(2 * GetPageSizeCached());
> + InternalScopedString res;
> RenderFrame(&res, common_flags()->stack_trace_format, i,
> frame->info.address, &frame->info,
> common_flags()->symbolize_vs_style,
> @@ -250,7 +250,7 @@ static void PrintMutex(const ReportMutex *rm) {
>
> static void PrintThread(const ReportThread *rt) {
> Decorator d;
> - if (rt->id == 0) // Little sense in describing the main thread.
> + if (rt->id == kMainTid) // Little sense in describing the main thread.
> return;
> Printf("%s", d.ThreadDescription());
> Printf(" Thread T%d", rt->id);
> @@ -394,7 +394,7 @@ void PrintReport(const ReportDesc *rep) {
>
> #else // #if !SANITIZER_GO
>
> -const int kMainThreadId = 1;
> +const u32 kMainGoroutineId = 1;
>
> void PrintStack(const ReportStack *ent) {
> if (ent == 0 || ent->frames == 0) {
> @@ -415,7 +415,7 @@ static void PrintMop(const ReportMop *mop, bool first) {
> Printf("%s at %p by ",
> (first ? (mop->write ? "Write" : "Read")
> : (mop->write ? "Previous write" : "Previous read")), mop->addr);
> - if (mop->tid == kMainThreadId)
> + if (mop->tid == kMainGoroutineId)
> Printf("main goroutine:\n");
> else
> Printf("goroutine %d:\n", mop->tid);
> @@ -428,7 +428,7 @@ static void PrintLocation(const ReportLocation *loc) {
> Printf("\n");
> Printf("Heap block of size %zu at %p allocated by ",
> loc->heap_chunk_size, loc->heap_chunk_start);
> - if (loc->tid == kMainThreadId)
> + if (loc->tid == kMainGoroutineId)
> Printf("main goroutine:\n");
> else
> Printf("goroutine %d:\n", loc->tid);
> @@ -448,7 +448,7 @@ static void PrintLocation(const ReportLocation *loc) {
> }
>
> static void PrintThread(const ReportThread *rt) {
> - if (rt->id == kMainThreadId)
> + if (rt->id == kMainGoroutineId)
> return;
> Printf("\n");
> Printf("Goroutine %d (%s) created at:\n",
> diff --git a/libsanitizer/tsan/tsan_rtl.cpp b/libsanitizer/tsan/tsan_rtl.cpp
> index 3d721eb95a2..0efa99788ab 100644
> --- a/libsanitizer/tsan/tsan_rtl.cpp
> +++ b/libsanitizer/tsan/tsan_rtl.cpp
> @@ -11,17 +11,19 @@
> // Main file (entry points) for the TSan run-time.
> //===----------------------------------------------------------------------===//
>
> +#include "tsan_rtl.h"
> +
> #include "sanitizer_common/sanitizer_atomic.h"
> #include "sanitizer_common/sanitizer_common.h"
> #include "sanitizer_common/sanitizer_file.h"
> #include "sanitizer_common/sanitizer_libc.h"
> -#include "sanitizer_common/sanitizer_stackdepot.h"
> #include "sanitizer_common/sanitizer_placement_new.h"
> +#include "sanitizer_common/sanitizer_stackdepot.h"
> #include "sanitizer_common/sanitizer_symbolizer.h"
> #include "tsan_defs.h"
> -#include "tsan_platform.h"
> -#include "tsan_rtl.h"
> +#include "tsan_interface.h"
> #include "tsan_mman.h"
> +#include "tsan_platform.h"
> #include "tsan_suppressions.h"
> #include "tsan_symbolize.h"
> #include "ubsan/ubsan_init.h"
> @@ -56,12 +58,23 @@ Context *ctx;
> bool OnFinalize(bool failed);
> void OnInitialize();
> #else
> +#include <dlfcn.h>
> SANITIZER_WEAK_CXX_DEFAULT_IMPL
> bool OnFinalize(bool failed) {
> +#if !SANITIZER_GO
> + if (auto *ptr = dlsym(RTLD_DEFAULT, "__tsan_on_finalize"))
> + return reinterpret_cast<decltype(&__tsan_on_finalize)>(ptr)(failed);
> +#endif
> return failed;
> }
> SANITIZER_WEAK_CXX_DEFAULT_IMPL
> -void OnInitialize() {}
> +void OnInitialize() {
> +#if !SANITIZER_GO
> + if (auto *ptr = dlsym(RTLD_DEFAULT, "__tsan_on_initialize")) {
> + return reinterpret_cast<decltype(&__tsan_on_initialize)>(ptr)();
> + }
> +#endif
> +}
> #endif
>
> static char thread_registry_placeholder[sizeof(ThreadRegistry)];
> @@ -77,12 +90,19 @@ static ThreadContextBase *CreateThreadContext(u32 tid) {
> new((void*)hdr) Trace();
> // We are going to use only a small part of the trace with the default
> // value of history_size. However, the constructor writes to the whole trace.
> - // Unmap the unused part.
> + // Release the unused part.
> uptr hdr_end = hdr + sizeof(Trace);
> hdr_end -= sizeof(TraceHeader) * (kTraceParts - TraceParts());
> hdr_end = RoundUp(hdr_end, GetPageSizeCached());
> - if (hdr_end < hdr + sizeof(Trace))
> - UnmapOrDie((void*)hdr_end, hdr + sizeof(Trace) - hdr_end);
> + if (hdr_end < hdr + sizeof(Trace)) {
> + ReleaseMemoryPagesToOS(hdr_end, hdr + sizeof(Trace));
> + uptr unused = hdr + sizeof(Trace) - hdr_end;
> + if (hdr_end != (uptr)MmapFixedNoAccess(hdr_end, unused)) {
> + Report("ThreadSanitizer: failed to mprotect(%p, %p)\n",
> + hdr_end, unused);
> + CHECK("unable to mprotect" && 0);
> + }
> + }
> void *mem = internal_alloc(MBlockThreadContex, sizeof(ThreadContext));
> return new(mem) ThreadContext(tid);
> }
> @@ -94,42 +114,45 @@ static const u32 kThreadQuarantineSize = 64;
> #endif
>
> Context::Context()
> - : initialized()
> - , report_mtx(MutexTypeReport, StatMtxReport)
> - , nreported()
> - , nmissed_expected()
> - , thread_registry(new(thread_registry_placeholder) ThreadRegistry(
> - CreateThreadContext, kMaxTid, kThreadQuarantineSize, kMaxTidReuse))
> - , racy_mtx(MutexTypeRacy, StatMtxRacy)
> - , racy_stacks()
> - , racy_addresses()
> - , fired_suppressions_mtx(MutexTypeFired, StatMtxFired)
> - , clock_alloc("clock allocator") {
> + : initialized(),
> + report_mtx(MutexTypeReport, StatMtxReport),
> + nreported(),
> + nmissed_expected(),
> + thread_registry(new (thread_registry_placeholder) ThreadRegistry(
> + CreateThreadContext, kMaxTid, kThreadQuarantineSize, kMaxTidReuse)),
> + racy_mtx(MutexTypeRacy, StatMtxRacy),
> + racy_stacks(),
> + racy_addresses(),
> + fired_suppressions_mtx(MutexTypeFired, StatMtxFired),
> + clock_alloc(LINKER_INITIALIZED, "clock allocator") {
> fired_suppressions.reserve(8);
> }
>
> // The objects are allocated in TLS, so one may rely on zero-initialization.
> -ThreadState::ThreadState(Context *ctx, int tid, int unique_id, u64 epoch,
> - unsigned reuse_count,
> - uptr stk_addr, uptr stk_size,
> +ThreadState::ThreadState(Context *ctx, u32 tid, int unique_id, u64 epoch,
> + unsigned reuse_count, uptr stk_addr, uptr stk_size,
> uptr tls_addr, uptr tls_size)
> - : fast_state(tid, epoch)
> - // Do not touch these, rely on zero initialization,
> - // they may be accessed before the ctor.
> - // , ignore_reads_and_writes()
> - // , ignore_interceptors()
> - , clock(tid, reuse_count)
> + : fast_state(tid, epoch)
> + // Do not touch these, rely on zero initialization,
> + // they may be accessed before the ctor.
> + // , ignore_reads_and_writes()
> + // , ignore_interceptors()
> + ,
> + clock(tid, reuse_count)
> #if !SANITIZER_GO
> - , jmp_bufs()
> + ,
> + jmp_bufs()
> #endif
> - , tid(tid)
> - , unique_id(unique_id)
> - , stk_addr(stk_addr)
> - , stk_size(stk_size)
> - , tls_addr(tls_addr)
> - , tls_size(tls_size)
> + ,
> + tid(tid),
> + unique_id(unique_id),
> + stk_addr(stk_addr),
> + stk_size(stk_size),
> + tls_addr(tls_addr),
> + tls_size(tls_size)
> #if !SANITIZER_GO
> - , last_sleep_clock(tid)
> + ,
> + last_sleep_clock(tid)
> #endif
> {
> }
> @@ -160,12 +183,12 @@ static void *BackgroundThread(void *arg) {
> } else if (internal_strcmp(flags()->profile_memory, "stderr") == 0) {
> mprof_fd = 2;
> } else {
> - InternalScopedString filename(kMaxPathLength);
> + InternalScopedString filename;
> filename.append("%s.%d", flags()->profile_memory, (int)internal_getpid());
> fd_t fd = OpenFile(filename.data(), WrOnly);
> if (fd == kInvalidFd) {
> Printf("ThreadSanitizer: failed to open memory profile file '%s'\n",
> - &filename[0]);
> + filename.data());
> } else {
> mprof_fd = fd;
> }
> @@ -351,6 +374,18 @@ static void TsanOnDeadlySignal(int signo, void *siginfo, void *context) {
> }
> #endif
>
> +void CheckUnwind() {
> + // There is high probability that interceptors will check-fail as well,
> + // on the other hand there is no sense in processing interceptors
> + // since we are going to die soon.
> + ScopedIgnoreInterceptors ignore;
> +#if !SANITIZER_GO
> + cur_thread()->ignore_sync++;
> + cur_thread()->ignore_reads_and_writes++;
> +#endif
> + PrintCurrentStackSlow(StackTrace::GetCurrentPc());
> +}
> +
> void Initialize(ThreadState *thr) {
> // Thread safe because done before all threads exist.
> static bool is_initialized = false;
> @@ -361,7 +396,7 @@ void Initialize(ThreadState *thr) {
> ScopedIgnoreInterceptors ignore;
> SanitizerToolName = "ThreadSanitizer";
> // Install tool-specific callbacks in sanitizer_common.
> - SetCheckFailedCallback(TsanCheckFailed);
> + SetCheckUnwindCallback(CheckUnwind);
>
> ctx = new(ctx_placeholder) Context;
> const char *env_name = SANITIZER_GO ? "GORACE" : "TSAN_OPTIONS";
> @@ -499,23 +534,27 @@ int Finalize(ThreadState *thr) {
> void ForkBefore(ThreadState *thr, uptr pc) {
> ctx->thread_registry->Lock();
> ctx->report_mtx.Lock();
> - // Ignore memory accesses in the pthread_atfork callbacks.
> - // If any of them triggers a data race we will deadlock
> - // on the report_mtx.
> - // We could ignore interceptors and sync operations as well,
> + // Suppress all reports in the pthread_atfork callbacks.
> + // Reports will deadlock on the report_mtx.
> + // We could ignore sync operations as well,
> // but so far it's unclear if it will do more good or harm.
> // Unnecessarily ignoring things can lead to false positives later.
> - ThreadIgnoreBegin(thr, pc);
> + thr->suppress_reports++;
> + // On OS X, REAL(fork) can call intercepted functions (OSSpinLockLock), and
> + // we'll assert in CheckNoLocks() unless we ignore interceptors.
> + thr->ignore_interceptors++;
> }
>
> void ForkParentAfter(ThreadState *thr, uptr pc) {
> - ThreadIgnoreEnd(thr, pc); // Begin is in ForkBefore.
> + thr->suppress_reports--; // Enabled in ForkBefore.
> + thr->ignore_interceptors--;
> ctx->report_mtx.Unlock();
> ctx->thread_registry->Unlock();
> }
>
> void ForkChildAfter(ThreadState *thr, uptr pc) {
> - ThreadIgnoreEnd(thr, pc); // Begin is in ForkBefore.
> + thr->suppress_reports--; // Enabled in ForkBefore.
> + thr->ignore_interceptors--;
> ctx->report_mtx.Unlock();
> ctx->thread_registry->Unlock();
>
> diff --git a/libsanitizer/tsan/tsan_rtl.h b/libsanitizer/tsan/tsan_rtl.h
> index 04d474e044e..3ae519d34da 100644
> --- a/libsanitizer/tsan/tsan_rtl.h
> +++ b/libsanitizer/tsan/tsan_rtl.h
> @@ -84,9 +84,6 @@ typedef Allocator::AllocatorCache AllocatorCache;
> Allocator *allocator();
> #endif
>
> -void TsanCheckFailed(const char *file, int line, const char *cond,
> - u64 v1, u64 v2);
> -
> const u64 kShadowRodata = (u64)-1; // .rodata shadow marker
>
> // FastState (from most significant bit):
> @@ -406,7 +403,7 @@ struct ThreadState {
> #if TSAN_COLLECT_STATS
> u64 stat[StatCnt];
> #endif
> - const int tid;
> + const u32 tid;
> const int unique_id;
> bool in_symbolizer;
> bool in_ignored_lib;
> @@ -447,9 +444,8 @@ struct ThreadState {
>
> const ReportDesc *current_report;
>
> - explicit ThreadState(Context *ctx, int tid, int unique_id, u64 epoch,
> - unsigned reuse_count,
> - uptr stk_addr, uptr stk_size,
> + explicit ThreadState(Context *ctx, u32 tid, int unique_id, u64 epoch,
> + unsigned reuse_count, uptr stk_addr, uptr stk_size,
> uptr tls_addr, uptr tls_size);
> };
>
> @@ -624,6 +620,7 @@ class ScopedReport : public ScopedReportBase {
> ScopedErrorReportLock lock_;
> };
>
> +bool ShouldReport(ThreadState *thr, ReportType typ);
> ThreadContext *IsThreadStackOrTls(uptr addr, bool *is_stack);
> void RestoreStack(int tid, const u64 epoch, VarSizeStackTrace *stk,
> MutexSet *mset, uptr *tag = nullptr);
> diff --git a/libsanitizer/tsan/tsan_rtl_mutex.cpp b/libsanitizer/tsan/tsan_rtl_mutex.cpp
> index 27897f0592b..0a8f3aa3ddb 100644
> --- a/libsanitizer/tsan/tsan_rtl_mutex.cpp
> +++ b/libsanitizer/tsan/tsan_rtl_mutex.cpp
> @@ -51,6 +51,8 @@ static void ReportMutexMisuse(ThreadState *thr, uptr pc, ReportType typ,
> // or false positives (e.g. unlock in a different thread).
> if (SANITIZER_GO)
> return;
> + if (!ShouldReport(thr, typ))
> + return;
> ThreadRegistryLock l(ctx->thread_registry);
> ScopedReport rep(typ);
> rep.AddMutex(mid);
> @@ -96,9 +98,8 @@ void MutexDestroy(ThreadState *thr, uptr pc, uptr addr, u32 flagz) {
> ctx->dd->MutexInit(&cb, &s->dd);
> }
> bool unlock_locked = false;
> - if (flags()->report_destroy_locked
> - && s->owner_tid != SyncVar::kInvalidTid
> - && !s->IsFlagSet(MutexFlagBroken)) {
> + if (flags()->report_destroy_locked && s->owner_tid != kInvalidTid &&
> + !s->IsFlagSet(MutexFlagBroken)) {
> s->SetFlags(MutexFlagBroken);
> unlock_locked = true;
> }
> @@ -107,7 +108,7 @@ void MutexDestroy(ThreadState *thr, uptr pc, uptr addr, u32 flagz) {
> if (!unlock_locked)
> s->Reset(thr->proc()); // must not reset it before the report is printed
> s->mtx.Unlock();
> - if (unlock_locked) {
> + if (unlock_locked && ShouldReport(thr, ReportTypeMutexDestroyLocked)) {
> ThreadRegistryLock l(ctx->thread_registry);
> ScopedReport rep(ReportTypeMutexDestroyLocked);
> rep.AddMutex(mid);
> @@ -169,7 +170,7 @@ void MutexPostLock(ThreadState *thr, uptr pc, uptr addr, u32 flagz, int rec) {
> thr->fast_state.IncrementEpoch();
> TraceAddEvent(thr, thr->fast_state, EventTypeLock, s->GetId());
> bool report_double_lock = false;
> - if (s->owner_tid == SyncVar::kInvalidTid) {
> + if (s->owner_tid == kInvalidTid) {
> CHECK_EQ(s->recursion, 0);
> s->owner_tid = thr->tid;
> s->last_lock = thr->fast_state.raw();
> @@ -229,7 +230,7 @@ int MutexUnlock(ThreadState *thr, uptr pc, uptr addr, u32 flagz) {
> s->recursion -= rec;
> if (s->recursion == 0) {
> StatInc(thr, StatMutexUnlock);
> - s->owner_tid = SyncVar::kInvalidTid;
> + s->owner_tid = kInvalidTid;
> ReleaseStoreImpl(thr, pc, &s->clock);
> } else {
> StatInc(thr, StatMutexRecUnlock);
> @@ -275,7 +276,7 @@ void MutexPostReadLock(ThreadState *thr, uptr pc, uptr addr, u32 flagz) {
> thr->fast_state.IncrementEpoch();
> TraceAddEvent(thr, thr->fast_state, EventTypeRLock, s->GetId());
> bool report_bad_lock = false;
> - if (s->owner_tid != SyncVar::kInvalidTid) {
> + if (s->owner_tid != kInvalidTid) {
> if (flags()->report_mutex_bugs && !s->IsFlagSet(MutexFlagBroken)) {
> s->SetFlags(MutexFlagBroken);
> report_bad_lock = true;
> @@ -314,7 +315,7 @@ void MutexReadUnlock(ThreadState *thr, uptr pc, uptr addr) {
> thr->fast_state.IncrementEpoch();
> TraceAddEvent(thr, thr->fast_state, EventTypeRUnlock, s->GetId());
> bool report_bad_unlock = false;
> - if (s->owner_tid != SyncVar::kInvalidTid) {
> + if (s->owner_tid != kInvalidTid) {
> if (flags()->report_mutex_bugs && !s->IsFlagSet(MutexFlagBroken)) {
> s->SetFlags(MutexFlagBroken);
> report_bad_unlock = true;
> @@ -344,7 +345,7 @@ void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr) {
> SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true);
> bool write = true;
> bool report_bad_unlock = false;
> - if (s->owner_tid == SyncVar::kInvalidTid) {
> + if (s->owner_tid == kInvalidTid) {
> // Seems to be read unlock.
> write = false;
> StatInc(thr, StatMutexReadUnlock);
> @@ -359,7 +360,7 @@ void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr) {
> s->recursion--;
> if (s->recursion == 0) {
> StatInc(thr, StatMutexUnlock);
> - s->owner_tid = SyncVar::kInvalidTid;
> + s->owner_tid = kInvalidTid;
> ReleaseStoreImpl(thr, pc, &s->clock);
> } else {
> StatInc(thr, StatMutexRecUnlock);
> @@ -387,7 +388,7 @@ void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr) {
> void MutexRepair(ThreadState *thr, uptr pc, uptr addr) {
> DPrintf("#%d: MutexRepair %zx\n", thr->tid, addr);
> SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true);
> - s->owner_tid = SyncVar::kInvalidTid;
> + s->owner_tid = kInvalidTid;
> s->recursion = 0;
> s->mtx.Unlock();
> }
> @@ -534,7 +535,7 @@ void AcquireReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c) {
> }
>
> void ReportDeadlock(ThreadState *thr, uptr pc, DDReport *r) {
> - if (r == 0)
> + if (r == 0 || !ShouldReport(thr, ReportTypeDeadlock))
> return;
> ThreadRegistryLock l(ctx->thread_registry);
> ScopedReport rep(ReportTypeDeadlock);
> diff --git a/libsanitizer/tsan/tsan_rtl_ppc64.S b/libsanitizer/tsan/tsan_rtl_ppc64.S
> index 9e533a71a9c..8285e21aa1e 100644
> --- a/libsanitizer/tsan/tsan_rtl_ppc64.S
> +++ b/libsanitizer/tsan/tsan_rtl_ppc64.S
> @@ -1,6 +1,5 @@
> #include "tsan_ppc_regs.h"
>
> - .machine altivec
> .section .text
> .hidden __tsan_setjmp
> .globl _setjmp
> diff --git a/libsanitizer/tsan/tsan_rtl_report.cpp b/libsanitizer/tsan/tsan_rtl_report.cpp
> index 208d0df44df..706794fdad1 100644
> --- a/libsanitizer/tsan/tsan_rtl_report.cpp
> +++ b/libsanitizer/tsan/tsan_rtl_report.cpp
> @@ -31,23 +31,6 @@ using namespace __sanitizer;
>
> static ReportStack *SymbolizeStack(StackTrace trace);
>
> -void TsanCheckFailed(const char *file, int line, const char *cond,
> - u64 v1, u64 v2) {
> - // There is high probability that interceptors will check-fail as well,
> - // on the other hand there is no sense in processing interceptors
> - // since we are going to die soon.
> - ScopedIgnoreInterceptors ignore;
> -#if !SANITIZER_GO
> - cur_thread()->ignore_sync++;
> - cur_thread()->ignore_reads_and_writes++;
> -#endif
> - Printf("FATAL: ThreadSanitizer CHECK failed: "
> - "%s:%d \"%s\" (0x%zx, 0x%zx)\n",
> - file, line, cond, (uptr)v1, (uptr)v2);
> - PrintCurrentStackSlow(StackTrace::GetCurrentPc());
> - Die();
> -}
> -
> // Can be overriden by an application/test to intercept reports.
> #ifdef TSAN_EXTERNAL_HOOKS
> bool OnReport(const ReportDesc *rep, bool suppressed);
> @@ -142,6 +125,34 @@ static ReportStack *SymbolizeStack(StackTrace trace) {
> return stack;
> }
>
> +bool ShouldReport(ThreadState *thr, ReportType typ) {
> + // We set thr->suppress_reports in the fork context.
> + // Taking any locking in the fork context can lead to deadlocks.
> + // If any locks are already taken, it's too late to do this check.
> + CheckNoLocks(thr);
> + // For the same reason check we didn't lock thread_registry yet.
> + if (SANITIZER_DEBUG)
> + ThreadRegistryLock l(ctx->thread_registry);
> + if (!flags()->report_bugs || thr->suppress_reports)
> + return false;
> + switch (typ) {
> + case ReportTypeSignalUnsafe:
> + return flags()->report_signal_unsafe;
> + case ReportTypeThreadLeak:
> +#if !SANITIZER_GO
> + // It's impossible to join phantom threads
> + // in the child after fork.
> + if (ctx->after_multithreaded_fork)
> + return false;
> +#endif
> + return flags()->report_thread_leaks;
> + case ReportTypeMutexDestroyLocked:
> + return flags()->report_destroy_locked;
> + default:
> + return true;
> + }
> +}
> +
> ScopedReportBase::ScopedReportBase(ReportType typ, uptr tag) {
> ctx->thread_registry->CheckLocked();
> void *mem = internal_alloc(MBlockReport, sizeof(ReportDesc));
> @@ -497,8 +508,10 @@ static bool HandleRacyAddress(ThreadState *thr, uptr addr_min, uptr addr_max) {
> }
>
> bool OutputReport(ThreadState *thr, const ScopedReport &srep) {
> - if (!flags()->report_bugs || thr->suppress_reports)
> - return false;
> + // These should have been checked in ShouldReport.
> + // It's too late to check them here, we have already taken locks.
> + CHECK(flags()->report_bugs);
> + CHECK(!thr->suppress_reports);
> atomic_store_relaxed(&ctx->last_symbolize_time_ns, NanoTime());
> const ReportDesc *rep = srep.GetReport();
> CHECK_EQ(thr->current_report, nullptr);
> @@ -589,7 +602,7 @@ void ReportRace(ThreadState *thr) {
> // at best it will cause deadlocks on internal mutexes.
> ScopedIgnoreInterceptors ignore;
>
> - if (!flags()->report_bugs)
> + if (!ShouldReport(thr, ReportTypeRace))
> return;
> if (!flags()->report_atomic_races && !RaceBetweenAtomicAndFree(thr))
> return;
> @@ -722,8 +735,7 @@ void PrintCurrentStack(ThreadState *thr, uptr pc) {
> // However, this solution is not reliable enough, please see dvyukov's comment
> // http://reviews.llvm.org/D19148#406208
> // Also see PR27280 comment 2 and 3 for breaking examples and analysis.
> -ALWAYS_INLINE
> -void PrintCurrentStackSlow(uptr pc) {
> +ALWAYS_INLINE USED void PrintCurrentStackSlow(uptr pc) {
> #if !SANITIZER_GO
> uptr bp = GET_CURRENT_FRAME();
> BufferedStackTrace *ptrace =
> diff --git a/libsanitizer/tsan/tsan_rtl_thread.cpp b/libsanitizer/tsan/tsan_rtl_thread.cpp
> index d80146735ea..6d1ccd8c9c7 100644
> --- a/libsanitizer/tsan/tsan_rtl_thread.cpp
> +++ b/libsanitizer/tsan/tsan_rtl_thread.cpp
> @@ -51,7 +51,7 @@ struct OnCreatedArgs {
>
> void ThreadContext::OnCreated(void *arg) {
> thr = 0;
> - if (tid == 0)
> + if (tid == kMainTid)
> return;
> OnCreatedArgs *args = static_cast<OnCreatedArgs *>(arg);
> if (!args->thr) // GCD workers don't have a parent thread.
> @@ -179,7 +179,7 @@ static void MaybeReportThreadLeak(ThreadContextBase *tctx_base, void *arg) {
>
> #if !SANITIZER_GO
> static void ReportIgnoresEnabled(ThreadContext *tctx, IgnoreSet *set) {
> - if (tctx->tid == 0) {
> + if (tctx->tid == kMainTid) {
> Printf("ThreadSanitizer: main thread finished with ignores enabled\n");
> } else {
> Printf("ThreadSanitizer: thread T%d %s finished with ignores enabled,"
> @@ -210,7 +210,7 @@ static void ThreadCheckIgnore(ThreadState *thr) {}
> void ThreadFinalize(ThreadState *thr) {
> ThreadCheckIgnore(thr);
> #if !SANITIZER_GO
> - if (!flags()->report_thread_leaks)
> + if (!ShouldReport(thr, ReportTypeThreadLeak))
> return;
> ThreadRegistryLock l(ctx->thread_registry);
> Vector<ThreadLeak> leaks;
> @@ -250,9 +250,10 @@ void ThreadStart(ThreadState *thr, int tid, tid_t os_id,
> uptr tls_size = 0;
> #if !SANITIZER_GO
> if (thread_type != ThreadType::Fiber)
> - GetThreadStackAndTls(tid == 0, &stk_addr, &stk_size, &tls_addr, &tls_size);
> + GetThreadStackAndTls(tid == kMainTid, &stk_addr, &stk_size, &tls_addr,
> + &tls_size);
>
> - if (tid) {
> + if (tid != kMainTid) {
> if (stk_addr && stk_size)
> MemoryRangeImitateWrite(thr, /*pc=*/ 1, stk_addr, stk_size);
>
> @@ -313,7 +314,7 @@ static bool ConsumeThreadByUid(ThreadContextBase *tctx, void *arg) {
> int ThreadConsumeTid(ThreadState *thr, uptr pc, uptr uid) {
> ConsumeThreadContext findCtx = {uid, nullptr};
> ctx->thread_registry->FindThread(ConsumeThreadByUid, &findCtx);
> - int tid = findCtx.tctx ? findCtx.tctx->tid : ThreadRegistry::kUnknownTid;
> + int tid = findCtx.tctx ? findCtx.tctx->tid : kInvalidTid;
> DPrintf("#%d: ThreadTid uid=%zu tid=%d\n", thr->tid, uid, tid);
> return tid;
> }
> diff --git a/libsanitizer/tsan/tsan_sync.cpp b/libsanitizer/tsan/tsan_sync.cpp
> index 17ddd50f128..ba24f98ae9f 100644
> --- a/libsanitizer/tsan/tsan_sync.cpp
> +++ b/libsanitizer/tsan/tsan_sync.cpp
> @@ -53,8 +53,8 @@ void SyncVar::Reset(Processor *proc) {
> }
>
> MetaMap::MetaMap()
> - : block_alloc_("heap block allocator")
> - , sync_alloc_("sync allocator") {
> + : block_alloc_(LINKER_INITIALIZED, "heap block allocator"),
> + sync_alloc_(LINKER_INITIALIZED, "sync allocator") {
> atomic_store(&uid_gen_, 0, memory_order_relaxed);
> }
>
> diff --git a/libsanitizer/tsan/tsan_sync.h b/libsanitizer/tsan/tsan_sync.h
> index 47f2739d8de..c4056f684d7 100644
> --- a/libsanitizer/tsan/tsan_sync.h
> +++ b/libsanitizer/tsan/tsan_sync.h
> @@ -50,13 +50,11 @@ enum MutexFlags {
> struct SyncVar {
> SyncVar();
>
> - static const int kInvalidTid = -1;
> -
> uptr addr; // overwritten by DenseSlabAlloc freelist
> Mutex mtx;
> u64 uid; // Globally unique id.
> u32 creation_stack_id;
> - int owner_tid; // Set only by exclusive owners.
> + u32 owner_tid; // Set only by exclusive owners.
> u64 last_lock;
> int recursion;
> atomic_uint32_t flags;
> @@ -130,8 +128,8 @@ class MetaMap {
> static const u32 kFlagMask = 3u << 30;
> static const u32 kFlagBlock = 1u << 30;
> static const u32 kFlagSync = 2u << 30;
> - typedef DenseSlabAlloc<MBlock, 1<<16, 1<<12> BlockAlloc;
> - typedef DenseSlabAlloc<SyncVar, 1<<16, 1<<10> SyncAlloc;
> + typedef DenseSlabAlloc<MBlock, 1 << 18, 1 << 12, kFlagMask> BlockAlloc;
> + typedef DenseSlabAlloc<SyncVar, 1 << 20, 1 << 10, kFlagMask> SyncAlloc;
> BlockAlloc block_alloc_;
> SyncAlloc sync_alloc_;
> atomic_uint64_t uid_gen_;
> diff --git a/libsanitizer/ubsan/ubsan_diag.cpp b/libsanitizer/ubsan/ubsan_diag.cpp
> index 1b2828d236d..ef2e495cac8 100644
> --- a/libsanitizer/ubsan/ubsan_diag.cpp
> +++ b/libsanitizer/ubsan/ubsan_diag.cpp
> @@ -278,7 +278,7 @@ static void PrintMemorySnippet(const Decorator &Decor, MemoryLocation Loc,
> }
>
> // Emit data.
> - InternalScopedString Buffer(1024);
> + InternalScopedString Buffer;
> for (uptr P = Min; P != Max; ++P) {
> unsigned char C = *reinterpret_cast<const unsigned char*>(P);
> Buffer.append("%s%02x", (P % 8 == 0) ? " " : " ", C);
> @@ -346,7 +346,7 @@ Diag::~Diag() {
> // All diagnostics should be printed under report mutex.
> ScopedReport::CheckLocked();
> Decorator Decor;
> - InternalScopedString Buffer(1024);
> + InternalScopedString Buffer;
>
> // Prepare a report that a monitor process can inspect.
> if (Level == DL_Error) {
> @@ -388,6 +388,10 @@ ScopedReport::ScopedReport(ReportOptions Opts, Location SummaryLoc,
> ScopedReport::~ScopedReport() {
> MaybePrintStackTrace(Opts.pc, Opts.bp);
> MaybeReportErrorSummary(SummaryLoc, Type);
> +
> + if (common_flags()->print_module_map >= 2)
> + DumpProcessMap();
> +
> if (flags()->halt_on_error)
> Die();
> }
> diff --git a/libsanitizer/ubsan/ubsan_flags.cpp b/libsanitizer/ubsan/ubsan_flags.cpp
> index 9a66bd37518..25cefd46ce2 100644
> --- a/libsanitizer/ubsan/ubsan_flags.cpp
> +++ b/libsanitizer/ubsan/ubsan_flags.cpp
> @@ -50,7 +50,6 @@ void InitializeFlags() {
> {
> CommonFlags cf;
> cf.CopyFrom(*common_flags());
> - cf.print_summary = false;
> cf.external_symbolizer_path = GetFlag("UBSAN_SYMBOLIZER_PATH");
> OverrideCommonFlags(cf);
> }
> diff --git a/libsanitizer/ubsan/ubsan_handlers.cpp b/libsanitizer/ubsan/ubsan_handlers.cpp
> index 2184625aa6e..e201e6bba22 100644
> --- a/libsanitizer/ubsan/ubsan_handlers.cpp
> +++ b/libsanitizer/ubsan/ubsan_handlers.cpp
> @@ -894,21 +894,6 @@ void __ubsan_handle_cfi_bad_type(CFICheckFailData *Data, ValueHandle Vtable,
>
> } // namespace __ubsan
>
> -void __ubsan::__ubsan_handle_cfi_bad_icall(CFIBadIcallData *CallData,
> - ValueHandle Function) {
> - GET_REPORT_OPTIONS(false);
> - CFICheckFailData Data = {CFITCK_ICall, CallData->Loc, CallData->Type};
> - handleCFIBadIcall(&Data, Function, Opts);
> -}
> -
> -void __ubsan::__ubsan_handle_cfi_bad_icall_abort(CFIBadIcallData *CallData,
> - ValueHandle Function) {
> - GET_REPORT_OPTIONS(true);
> - CFICheckFailData Data = {CFITCK_ICall, CallData->Loc, CallData->Type};
> - handleCFIBadIcall(&Data, Function, Opts);
> - Die();
> -}
> -
> void __ubsan::__ubsan_handle_cfi_check_fail(CFICheckFailData *Data,
> ValueHandle Value,
> uptr ValidVtable) {
> diff --git a/libsanitizer/ubsan/ubsan_handlers.h b/libsanitizer/ubsan/ubsan_handlers.h
> index 9f412353fc0..219fb15de55 100644
> --- a/libsanitizer/ubsan/ubsan_handlers.h
> +++ b/libsanitizer/ubsan/ubsan_handlers.h
> @@ -215,20 +215,12 @@ enum CFITypeCheckKind : unsigned char {
> CFITCK_VMFCall,
> };
>
> -struct CFIBadIcallData {
> - SourceLocation Loc;
> - const TypeDescriptor &Type;
> -};
> -
> struct CFICheckFailData {
> CFITypeCheckKind CheckKind;
> SourceLocation Loc;
> const TypeDescriptor &Type;
> };
>
> -/// \brief Handle control flow integrity failure for indirect function calls.
> -RECOVERABLE(cfi_bad_icall, CFIBadIcallData *Data, ValueHandle Function)
> -
> /// \brief Handle control flow integrity failures.
> RECOVERABLE(cfi_check_fail, CFICheckFailData *Data, ValueHandle Function,
> uptr VtableIsValid)
> diff --git a/libsanitizer/ubsan/ubsan_init.cpp b/libsanitizer/ubsan/ubsan_init.cpp
> index e0be5a72ec4..9931d85bf40 100644
> --- a/libsanitizer/ubsan/ubsan_init.cpp
> +++ b/libsanitizer/ubsan/ubsan_init.cpp
> @@ -33,6 +33,11 @@ static void CommonInit() {
> InitializeSuppressions();
> }
>
> +static void UbsanDie() {
> + if (common_flags()->print_module_map >= 1)
> + DumpProcessMap();
> +}
> +
> static void CommonStandaloneInit() {
> SanitizerToolName = GetSanititizerToolName();
> CacheBinaryName();
> @@ -42,6 +47,10 @@ static void CommonStandaloneInit() {
> AndroidLogInit();
> InitializeCoverage(common_flags()->coverage, common_flags()->coverage_dir);
> CommonInit();
> +
> + // Only add die callback when running in standalone mode to avoid printing
> + // the same information from multiple sanitizers' output
> + AddDieCallback(UbsanDie);
> Symbolizer::LateInitialize();
> }
>
> diff --git a/libsanitizer/ubsan/ubsan_monitor.cpp b/libsanitizer/ubsan/ubsan_monitor.cpp
> index d064e95f76f..69dd986f9bd 100644
> --- a/libsanitizer/ubsan/ubsan_monitor.cpp
> +++ b/libsanitizer/ubsan/ubsan_monitor.cpp
> @@ -17,7 +17,7 @@ using namespace __ubsan;
> UndefinedBehaviorReport::UndefinedBehaviorReport(const char *IssueKind,
> Location &Loc,
> InternalScopedString &Msg)
> - : IssueKind(IssueKind), Loc(Loc), Buffer(Msg.length() + 1) {
> + : IssueKind(IssueKind), Loc(Loc) {
> // We have the common sanitizer reporting lock, so it's safe to register a
> // new UB report.
> RegisterUndefinedBehaviorReport(this);
> @@ -52,9 +52,9 @@ void __ubsan::__ubsan_get_current_report_data(const char **OutIssueKind,
>
> // Ensure that the first character of the diagnostic text can't start with a
> // lowercase letter.
> - char FirstChar = Buf.data()[0];
> + char FirstChar = *Buf.data();
> if (FirstChar >= 'a' && FirstChar <= 'z')
> - Buf.data()[0] = FirstChar - 'a' + 'A';
> + *Buf.data() += 'A' - 'a';
>
> *OutIssueKind = CurrentUBR->IssueKind;
> *OutMessage = Buf.data();
> diff --git a/libsanitizer/ubsan/ubsan_platform.h b/libsanitizer/ubsan/ubsan_platform.h
> index 98542fcea96..51e535d1e22 100644
> --- a/libsanitizer/ubsan/ubsan_platform.h
> +++ b/libsanitizer/ubsan/ubsan_platform.h
> @@ -12,16 +12,14 @@
> #ifndef UBSAN_PLATFORM_H
> #define UBSAN_PLATFORM_H
>
> -#ifndef CAN_SANITIZE_UB
> // Other platforms should be easy to add, and probably work as-is.
> #if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || \
> - defined(__NetBSD__) || \
> + defined(__NetBSD__) || defined(__DragonFly__) || \
> (defined(__sun__) && defined(__svr4__)) || \
> defined(_WIN32) || defined(__Fuchsia__) || defined(__rtems__)
> # define CAN_SANITIZE_UB 1
> #else
> # define CAN_SANITIZE_UB 0
> #endif
> -#endif //CAN_SANITIZE_UB
>
> #endif
> --
> 2.31.1
>
--
BR,
Hongtao
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH] libsanitizer: merge from master
2021-06-04 7:32 ` [PATCH] libsanitizer: merge from master Hongtao Liu
@ 2021-06-04 7:36 ` Martin Liška
2021-06-04 7:53 ` Hongtao Liu
0 siblings, 1 reply; 17+ messages in thread
From: Martin Liška @ 2021-06-04 7:36 UTC (permalink / raw)
To: Hongtao Liu; +Cc: GCC Patches
On 6/4/21 9:32 AM, Hongtao Liu wrote:
> Hi:
> I'm currently working on support hwasan with Intel LAM, i found
Nice!
> there's gap between gcc libsanitizer and corresponding llvm
> compiler-rt, so could you help to sync from llvm to gcc libsanitizer.
> Or is there's any instructions i can follow to sync it myself?
Yes, please follow instructions mentioned in here:
libsanitizer/HOWTO_MERGE
Martin
>
> On Thu, May 13, 2021 at 3:50 PM Martin Liška <mliska@suse.cz> wrote:
>>
>> I'm planning to do merge from master twice a year.
>> This merge was tested on x86_64-linux-gnu and ppc64le-linux-gnu
>> and survives regression tests.
>>
>> Pushed to master.
>> Thanks,
>> Martin
>>
>> Merged revision: f58e0513dd95944b81ce7a6e7b49ba656de7d75f
>> ---
>> libsanitizer/MERGE | 2 +-
>> libsanitizer/asan/asan_allocator.cpp | 32 +-
>> libsanitizer/asan/asan_descriptions.cpp | 19 +-
>> libsanitizer/asan/asan_descriptions.h | 13 +-
>> libsanitizer/asan/asan_errors.cpp | 7 +-
>> libsanitizer/asan/asan_fake_stack.cpp | 2 +-
>> libsanitizer/asan/asan_fuchsia.cpp | 2 +-
>> libsanitizer/asan/asan_globals.cpp | 19 +
>> libsanitizer/asan/asan_interceptors.cpp | 41 +-
>> libsanitizer/asan/asan_interceptors.h | 21 +-
>> libsanitizer/asan/asan_linux.cpp | 3 +-
>> libsanitizer/asan/asan_mapping.h | 25 +-
>> libsanitizer/asan/asan_new_delete.cpp | 2 +-
>> libsanitizer/asan/asan_poisoning.cpp | 2 +-
>> libsanitizer/asan/asan_posix.cpp | 2 +-
>> libsanitizer/asan/asan_rtl.cpp | 20 +-
>> libsanitizer/asan/asan_stack.h | 9 -
>> libsanitizer/asan/asan_thread.cpp | 51 +-
>> libsanitizer/asan/asan_thread.h | 6 +-
>> libsanitizer/asan/asan_win.cpp | 2 +-
>> libsanitizer/builtins/assembly.h | 98 +++-
>> libsanitizer/hwasan/hwasan.cpp | 19 +-
>> libsanitizer/hwasan/hwasan.h | 41 +-
>> libsanitizer/hwasan/hwasan_allocator.cpp | 28 +-
>> libsanitizer/hwasan/hwasan_allocator.h | 19 +-
>> libsanitizer/hwasan/hwasan_checks.h | 5 +-
>> libsanitizer/hwasan/hwasan_dynamic_shadow.cpp | 16 +-
>> libsanitizer/hwasan/hwasan_flags.h | 2 +
>> libsanitizer/hwasan/hwasan_flags.inc | 9 +
>> libsanitizer/hwasan/hwasan_interceptors.cpp | 3 +-
>> .../hwasan/hwasan_interceptors_vfork.S | 3 +
>> .../hwasan/hwasan_interface_internal.h | 3 +
>> libsanitizer/hwasan/hwasan_linux.cpp | 41 +-
>> libsanitizer/hwasan/hwasan_mapping.h | 2 +
>> libsanitizer/hwasan/hwasan_memintrinsics.cpp | 4 +-
>> libsanitizer/hwasan/hwasan_new_delete.cpp | 39 ++
>> libsanitizer/hwasan/hwasan_report.cpp | 26 +-
>> libsanitizer/hwasan/hwasan_setjmp.S | 6 +
>> .../hwasan/hwasan_tag_mismatch_aarch64.S | 6 +
>> libsanitizer/hwasan/hwasan_thread.cpp | 15 +-
>> libsanitizer/hwasan/hwasan_thread.h | 4 +-
>> libsanitizer/hwasan/hwasan_thread_list.h | 90 ++--
>> .../include/sanitizer/common_interface_defs.h | 3 +
>> .../include/sanitizer/dfsan_interface.h | 16 +
>> .../include/sanitizer/hwasan_interface.h | 3 +
>> .../include/sanitizer/memprof_interface.h | 5 +
>> .../include/sanitizer/tsan_interface.h | 17 +-
>> .../include/sanitizer/tsan_interface_atomic.h | 2 +-
>> .../interception/interception_linux.cpp | 6 +-
>> .../interception/interception_linux.h | 6 +-
>> .../interception/interception_win.cpp | 6 +-
>> libsanitizer/lsan/lsan_allocator.cpp | 26 +-
>> libsanitizer/lsan/lsan_allocator.h | 2 +-
>> libsanitizer/lsan/lsan_common.cpp | 234 ++++++---
>> libsanitizer/lsan/lsan_common.h | 9 +-
>> libsanitizer/lsan/lsan_common_fuchsia.cpp | 4 +-
>> libsanitizer/lsan/lsan_fuchsia.h | 2 +-
>> libsanitizer/lsan/lsan_interceptors.cpp | 2 +-
>> libsanitizer/lsan/lsan_posix.cpp | 6 +-
>> libsanitizer/lsan/lsan_thread.cpp | 2 +-
>> .../sanitizer_allocator_combined.h | 4 +-
>> .../sanitizer_allocator_primary32.h | 3 +-
>> .../sanitizer_allocator_primary64.h | 93 +++-
>> .../sanitizer_allocator_size_class_map.h | 2 +-
>> .../sanitizer_atomic_clang_mips.h | 8 +-
>> .../sanitizer_chained_origin_depot.cpp | 108 +++++
>> .../sanitizer_chained_origin_depot.h | 88 ++++
>> .../sanitizer_common/sanitizer_common.cpp | 10 +-
>> .../sanitizer_common/sanitizer_common.h | 82 +++-
>> .../sanitizer_common_interceptors.inc | 19 +-
>> .../sanitizer_common_interceptors_ioctl.inc | 6 +-
>> ...er_common_interceptors_vfork_aarch64.inc.S | 5 +
>> .../sanitizer_common_interface.inc | 1 +
>> .../sanitizer_common_libcdep.cpp | 7 +-
>> .../sanitizer_common/sanitizer_file.cpp | 13 +
>> .../sanitizer_common/sanitizer_file.h | 1 +
>> .../sanitizer_common/sanitizer_flags.cpp | 7 +
>> .../sanitizer_common/sanitizer_flags.inc | 2 +
>> .../sanitizer_common/sanitizer_fuchsia.cpp | 72 +--
>> .../sanitizer_interface_internal.h | 4 +
>> .../sanitizer_internal_defs.h | 3 +
>> .../sanitizer_common/sanitizer_libignore.cpp | 2 +-
>> .../sanitizer_common/sanitizer_linux.cpp | 72 +--
>> .../sanitizer_common/sanitizer_linux.h | 3 +-
>> .../sanitizer_linux_libcdep.cpp | 447 ++++++++++--------
>> .../sanitizer_local_address_space_view.h | 2 +-
>> .../sanitizer_common/sanitizer_mac.cpp | 141 +++++-
>> libsanitizer/sanitizer_common/sanitizer_mac.h | 37 --
>> .../sanitizer_common/sanitizer_malloc_mac.inc | 6 +-
>> .../sanitizer_common/sanitizer_netbsd.cpp | 6 +
>> .../sanitizer_common/sanitizer_platform.h | 27 +-
>> .../sanitizer_platform_interceptors.h | 113 +++--
>> .../sanitizer_platform_limits_freebsd.cpp | 3 +
>> .../sanitizer_platform_limits_linux.cpp | 7 +-
>> .../sanitizer_platform_limits_posix.cpp | 85 ++--
>> .../sanitizer_platform_limits_posix.h | 4 +-
>> .../sanitizer_common/sanitizer_posix.cpp | 4 +-
>> .../sanitizer_common/sanitizer_posix.h | 4 +
>> .../sanitizer_posix_libcdep.cpp | 2 +-
>> .../sanitizer_common/sanitizer_printf.cpp | 57 ++-
>> .../sanitizer_procmaps_common.cpp | 2 +-
>> .../sanitizer_procmaps_mac.cpp | 4 +-
>> .../sanitizer_procmaps_solaris.cpp | 4 +-
>> .../sanitizer_common/sanitizer_ptrauth.h | 20 +-
>> .../sanitizer_common/sanitizer_stackdepot.cpp | 3 +-
>> .../sanitizer_common/sanitizer_stacktrace.cpp | 20 +-
>> .../sanitizer_common/sanitizer_stacktrace.h | 2 -
>> .../sanitizer_stacktrace_libcdep.cpp | 8 +-
>> .../sanitizer_stoptheworld_linux_libcdep.cpp | 5 +
>> .../sanitizer_suppressions.cpp | 4 +-
>> .../sanitizer_symbolizer_libcdep.cpp | 2 +-
>> .../sanitizer_symbolizer_markup.cpp | 4 +
>> .../sanitizer_symbolizer_posix_libcdep.cpp | 11 +-
>> .../sanitizer_symbolizer_report.cpp | 6 +-
>> .../sanitizer_symbolizer_win.cpp | 18 +-
>> .../sanitizer_termination.cpp | 33 +-
>> .../sanitizer_thread_registry.cpp | 14 +-
>> .../sanitizer_thread_registry.h | 7 +-
>> .../sanitizer_tls_get_addr.cpp | 79 ++--
>> .../sanitizer_common/sanitizer_tls_get_addr.h | 21 +-
>> .../sanitizer_common/sanitizer_unwind_win.cpp | 7 +
>> .../sanitizer_common/sanitizer_win.cpp | 84 ++--
>> libsanitizer/tsan/tsan_clock.cpp | 37 +-
>> libsanitizer/tsan/tsan_clock.h | 16 +-
>> libsanitizer/tsan/tsan_defs.h | 2 -
>> libsanitizer/tsan/tsan_dense_alloc.h | 32 +-
>> libsanitizer/tsan/tsan_external.cpp | 4 +-
>> libsanitizer/tsan/tsan_interceptors_mac.cpp | 1 +
>> libsanitizer/tsan/tsan_interceptors_posix.cpp | 149 ++++--
>> libsanitizer/tsan/tsan_interface.cpp | 8 +-
>> libsanitizer/tsan/tsan_interface.h | 9 +-
>> libsanitizer/tsan/tsan_interface_inl.h | 22 +-
>> libsanitizer/tsan/tsan_mman.cpp | 2 +-
>> libsanitizer/tsan/tsan_platform.h | 121 ++++-
>> libsanitizer/tsan/tsan_platform_linux.cpp | 23 +-
>> libsanitizer/tsan/tsan_platform_mac.cpp | 9 +-
>> libsanitizer/tsan/tsan_platform_posix.cpp | 2 +-
>> libsanitizer/tsan/tsan_report.cpp | 14 +-
>> libsanitizer/tsan/tsan_rtl.cpp | 129 +++--
>> libsanitizer/tsan/tsan_rtl.h | 11 +-
>> libsanitizer/tsan/tsan_rtl_mutex.cpp | 25 +-
>> libsanitizer/tsan/tsan_rtl_ppc64.S | 1 -
>> libsanitizer/tsan/tsan_rtl_report.cpp | 56 ++-
>> libsanitizer/tsan/tsan_rtl_thread.cpp | 13 +-
>> libsanitizer/tsan/tsan_sync.cpp | 4 +-
>> libsanitizer/tsan/tsan_sync.h | 8 +-
>> libsanitizer/ubsan/ubsan_diag.cpp | 8 +-
>> libsanitizer/ubsan/ubsan_flags.cpp | 1 -
>> libsanitizer/ubsan/ubsan_handlers.cpp | 15 -
>> libsanitizer/ubsan/ubsan_handlers.h | 8 -
>> libsanitizer/ubsan/ubsan_init.cpp | 9 +
>> libsanitizer/ubsan/ubsan_monitor.cpp | 6 +-
>> libsanitizer/ubsan/ubsan_platform.h | 4 +-
>> 153 files changed, 2538 insertions(+), 1239 deletions(-)
>> create mode 100644 libsanitizer/sanitizer_common/sanitizer_chained_origin_depot.cpp
>> create mode 100644 libsanitizer/sanitizer_common/sanitizer_chained_origin_depot.h
>>
>> diff --git a/libsanitizer/MERGE b/libsanitizer/MERGE
>> index 0fb64a9567c..c4731d0866c 100644
>> --- a/libsanitizer/MERGE
>> +++ b/libsanitizer/MERGE
>> @@ -1,4 +1,4 @@
>> -6e7dd1e3e1170080b76b5dcc5716bdd974343233
>> +f58e0513dd95944b81ce7a6e7b49ba656de7d75f
>>
>> The first line of this file holds the git revision number of the
>> last merge done from the master library sources.
>> diff --git a/libsanitizer/asan/asan_allocator.cpp b/libsanitizer/asan/asan_allocator.cpp
>> index 58b496a3ca4..7c8bb504332 100644
>> --- a/libsanitizer/asan/asan_allocator.cpp
>> +++ b/libsanitizer/asan/asan_allocator.cpp
>> @@ -476,7 +476,7 @@ struct Allocator {
>> return false;
>> if (m->Beg() != addr) return false;
>> AsanThread *t = GetCurrentThread();
>> - m->SetAllocContext(t ? t->tid() : 0, StackDepotPut(*stack));
>> + m->SetAllocContext(t ? t->tid() : kMainTid, StackDepotPut(*stack));
>> return true;
>> }
>>
>> @@ -570,7 +570,7 @@ struct Allocator {
>> m->SetUsedSize(size);
>> m->user_requested_alignment_log = user_requested_alignment_log;
>>
>> - m->SetAllocContext(t ? t->tid() : 0, StackDepotPut(*stack));
>> + m->SetAllocContext(t ? t->tid() : kMainTid, StackDepotPut(*stack));
>>
>> uptr size_rounded_down_to_granularity =
>> RoundDownTo(size, SHADOW_GRANULARITY);
>> @@ -1183,6 +1183,34 @@ IgnoreObjectResult IgnoreObjectLocked(const void *p) {
>> m->lsan_tag = __lsan::kIgnored;
>> return kIgnoreObjectSuccess;
>> }
>> +
>> +void GetAdditionalThreadContextPtrs(ThreadContextBase *tctx, void *ptrs) {
>> + // Look for the arg pointer of threads that have been created or are running.
>> + // This is necessary to prevent false positive leaks due to the AsanThread
>> + // holding the only live reference to a heap object. This can happen because
>> + // the `pthread_create()` interceptor doesn't wait for the child thread to
>> + // start before returning and thus loosing the the only live reference to the
>> + // heap object on the stack.
>> +
>> + __asan::AsanThreadContext *atctx =
>> + reinterpret_cast<__asan::AsanThreadContext *>(tctx);
>> + __asan::AsanThread *asan_thread = atctx->thread;
>> +
>> + // Note ThreadStatusRunning is required because there is a small window where
>> + // the thread status switches to `ThreadStatusRunning` but the `arg` pointer
>> + // still isn't on the stack yet.
>> + if (atctx->status != ThreadStatusCreated &&
>> + atctx->status != ThreadStatusRunning)
>> + return;
>> +
>> + uptr thread_arg = reinterpret_cast<uptr>(asan_thread->get_arg());
>> + if (!thread_arg)
>> + return;
>> +
>> + auto ptrsVec = reinterpret_cast<InternalMmapVector<uptr> *>(ptrs);
>> + ptrsVec->push_back(thread_arg);
>> +}
>> +
>> } // namespace __lsan
>>
>> // ---------------------- Interface ---------------- {{{1
>> diff --git a/libsanitizer/asan/asan_descriptions.cpp b/libsanitizer/asan/asan_descriptions.cpp
>> index 153c874a4e7..2ba8a02f841 100644
>> --- a/libsanitizer/asan/asan_descriptions.cpp
>> +++ b/libsanitizer/asan/asan_descriptions.cpp
>> @@ -44,11 +44,11 @@ void DescribeThread(AsanThreadContext *context) {
>> CHECK(context);
>> asanThreadRegistry().CheckLocked();
>> // No need to announce the main thread.
>> - if (context->tid == 0 || context->announced) {
>> + if (context->tid == kMainTid || context->announced) {
>> return;
>> }
>> context->announced = true;
>> - InternalScopedString str(1024);
>> + InternalScopedString str;
>> str.append("Thread %s", AsanThreadIdAndName(context).c_str());
>> if (context->parent_tid == kInvalidTid) {
>> str.append(" created by unknown thread\n");
>> @@ -77,7 +77,6 @@ static bool GetShadowKind(uptr addr, ShadowKind *shadow_kind) {
>> } else if (AddrIsInLowShadow(addr)) {
>> *shadow_kind = kShadowKindLow;
>> } else {
>> - CHECK(0 && "Address is not in memory and not in shadow?");
>> return false;
>> }
>> return true;
>> @@ -126,7 +125,7 @@ static void GetAccessToHeapChunkInformation(ChunkAccess *descr,
>>
>> static void PrintHeapChunkAccess(uptr addr, const ChunkAccess &descr) {
>> Decorator d;
>> - InternalScopedString str(4096);
>> + InternalScopedString str;
>> str.append("%s", d.Location());
>> switch (descr.access_type) {
>> case kAccessTypeLeft:
>> @@ -243,7 +242,7 @@ static void PrintAccessAndVarIntersection(const StackVarDescr &var, uptr addr,
>> else if (addr >= prev_var_end && addr - prev_var_end >= var.beg - addr_end)
>> pos_descr = "underflows";
>> }
>> - InternalScopedString str(1024);
>> + InternalScopedString str;
>> str.append(" [%zd, %zd)", var.beg, var_end);
>> // Render variable name.
>> str.append(" '");
>> @@ -276,7 +275,7 @@ bool DescribeAddressIfStack(uptr addr, uptr access_size) {
>> // Global descriptions
>> static void DescribeAddressRelativeToGlobal(uptr addr, uptr access_size,
>> const __asan_global &g) {
>> - InternalScopedString str(4096);
>> + InternalScopedString str;
>> Decorator d;
>> str.append("%s", d.Location());
>> if (addr < g.beg) {
>> @@ -464,7 +463,13 @@ AddressDescription::AddressDescription(uptr addr, uptr access_size,
>> return;
>> }
>> data.kind = kAddressKindWild;
>> - addr = 0;
>> + data.wild.addr = addr;
>> + data.wild.access_size = access_size;
>> +}
>> +
>> +void WildAddressDescription::Print() const {
>> + Printf("Address %p is a wild pointer inside of access range of size %p.\n",
>> + addr, access_size);
>> }
>>
>> void PrintAddressDescription(uptr addr, uptr access_size,
>> diff --git a/libsanitizer/asan/asan_descriptions.h b/libsanitizer/asan/asan_descriptions.h
>> index ee0e2061559..650e2eb9173 100644
>> --- a/libsanitizer/asan/asan_descriptions.h
>> +++ b/libsanitizer/asan/asan_descriptions.h
>> @@ -146,6 +146,13 @@ struct StackAddressDescription {
>> bool GetStackAddressInformation(uptr addr, uptr access_size,
>> StackAddressDescription *descr);
>>
>> +struct WildAddressDescription {
>> + uptr addr;
>> + uptr access_size;
>> +
>> + void Print() const;
>> +};
>> +
>> struct GlobalAddressDescription {
>> uptr addr;
>> // Assume address is close to at most four globals.
>> @@ -193,7 +200,7 @@ class AddressDescription {
>> HeapAddressDescription heap;
>> StackAddressDescription stack;
>> GlobalAddressDescription global;
>> - uptr addr;
>> + WildAddressDescription wild;
>> };
>> };
>>
>> @@ -211,7 +218,7 @@ class AddressDescription {
>> uptr Address() const {
>> switch (data.kind) {
>> case kAddressKindWild:
>> - return data.addr;
>> + return data.wild.addr;
>> case kAddressKindShadow:
>> return data.shadow.addr;
>> case kAddressKindHeap:
>> @@ -226,7 +233,7 @@ class AddressDescription {
>> void Print(const char *bug_descr = nullptr) const {
>> switch (data.kind) {
>> case kAddressKindWild:
>> - Printf("Address %p is a wild pointer.\n", data.addr);
>> + data.wild.Print();
>> return;
>> case kAddressKindShadow:
>> return data.shadow.Print();
>> diff --git a/libsanitizer/asan/asan_errors.cpp b/libsanitizer/asan/asan_errors.cpp
>> index 541c6e0353b..e68e6971f96 100644
>> --- a/libsanitizer/asan/asan_errors.cpp
>> +++ b/libsanitizer/asan/asan_errors.cpp
>> @@ -343,7 +343,8 @@ void ErrorODRViolation::Print() {
>> Report("ERROR: AddressSanitizer: %s (%p):\n", scariness.GetDescription(),
>> global1.beg);
>> Printf("%s", d.Default());
>> - InternalScopedString g1_loc(256), g2_loc(256);
>> + InternalScopedString g1_loc;
>> + InternalScopedString g2_loc;
>> PrintGlobalLocation(&g1_loc, global1);
>> PrintGlobalLocation(&g2_loc, global2);
>> Printf(" [1] size=%zd '%s' %s\n", global1.size,
>> @@ -360,7 +361,7 @@ void ErrorODRViolation::Print() {
>> Report(
>> "HINT: if you don't care about these errors you may set "
>> "ASAN_OPTIONS=detect_odr_violation=0\n");
>> - InternalScopedString error_msg(256);
>> + InternalScopedString error_msg;
>> error_msg.append("%s: global '%s' at %s", scariness.GetDescription(),
>> MaybeDemangleGlobalName(global1.name), g1_loc.data());
>> ReportErrorSummary(error_msg.data());
>> @@ -554,7 +555,7 @@ static void PrintShadowMemoryForAddress(uptr addr) {
>> uptr shadow_addr = MemToShadow(addr);
>> const uptr n_bytes_per_row = 16;
>> uptr aligned_shadow = shadow_addr & ~(n_bytes_per_row - 1);
>> - InternalScopedString str(4096 * 8);
>> + InternalScopedString str;
>> str.append("Shadow bytes around the buggy address:\n");
>> for (int i = -5; i <= 5; i++) {
>> uptr row_shadow_addr = aligned_shadow + i * n_bytes_per_row;
>> diff --git a/libsanitizer/asan/asan_fake_stack.cpp b/libsanitizer/asan/asan_fake_stack.cpp
>> index 295e6debc96..1f873fec7d7 100644
>> --- a/libsanitizer/asan/asan_fake_stack.cpp
>> +++ b/libsanitizer/asan/asan_fake_stack.cpp
>> @@ -65,7 +65,7 @@ FakeStack *FakeStack::Create(uptr stack_size_log) {
>> void FakeStack::Destroy(int tid) {
>> PoisonAll(0);
>> if (Verbosity() >= 2) {
>> - InternalScopedString str(kNumberOfSizeClasses * 50);
>> + InternalScopedString str;
>> for (uptr class_id = 0; class_id < kNumberOfSizeClasses; class_id++)
>> str.append("%zd: %zd/%zd; ", class_id, hint_position_[class_id],
>> NumberOfFrames(stack_size_log(), class_id));
>> diff --git a/libsanitizer/asan/asan_fuchsia.cpp b/libsanitizer/asan/asan_fuchsia.cpp
>> index 6c61344f87c..b0c7255144a 100644
>> --- a/libsanitizer/asan/asan_fuchsia.cpp
>> +++ b/libsanitizer/asan/asan_fuchsia.cpp
>> @@ -81,7 +81,7 @@ void AsanTSDInit(void (*destructor)(void *tsd)) {
>> void PlatformTSDDtor(void *tsd) { UNREACHABLE(__func__); }
>>
>> static inline size_t AsanThreadMmapSize() {
>> - return RoundUpTo(sizeof(AsanThread), PAGE_SIZE);
>> + return RoundUpTo(sizeof(AsanThread), _zx_system_get_page_size());
>> }
>>
>> struct AsanThread::InitOptions {
>> diff --git a/libsanitizer/asan/asan_globals.cpp b/libsanitizer/asan/asan_globals.cpp
>> index e045c31cd1c..9d7dbc6f264 100644
>> --- a/libsanitizer/asan/asan_globals.cpp
>> +++ b/libsanitizer/asan/asan_globals.cpp
>> @@ -154,6 +154,23 @@ static void CheckODRViolationViaIndicator(const Global *g) {
>> }
>> }
>>
>> +// Check ODR violation for given global G by checking if it's already poisoned.
>> +// We use this method in case compiler doesn't use private aliases for global
>> +// variables.
>> +static void CheckODRViolationViaPoisoning(const Global *g) {
>> + if (__asan_region_is_poisoned(g->beg, g->size_with_redzone)) {
>> + // This check may not be enough: if the first global is much larger
>> + // the entire redzone of the second global may be within the first global.
>> + for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) {
>> + if (g->beg == l->g->beg &&
>> + (flags()->detect_odr_violation >= 2 || g->size != l->g->size) &&
>> + !IsODRViolationSuppressed(g->name))
>> + ReportODRViolation(g, FindRegistrationSite(g),
>> + l->g, FindRegistrationSite(l->g));
>> + }
>> + }
>> +}
>> +
>> // Clang provides two different ways for global variables protection:
>> // it can poison the global itself or its private alias. In former
>> // case we may poison same symbol multiple times, that can help us to
>> @@ -199,6 +216,8 @@ static void RegisterGlobal(const Global *g) {
>> // where two globals with the same name are defined in different modules.
>> if (UseODRIndicator(g))
>> CheckODRViolationViaIndicator(g);
>> + else
>> + CheckODRViolationViaPoisoning(g);
>> }
>> if (CanPoisonMemory())
>> PoisonRedZones(*g);
>> diff --git a/libsanitizer/asan/asan_interceptors.cpp b/libsanitizer/asan/asan_interceptors.cpp
>> index 4e68b3b0b47..9db7db89fa1 100644
>> --- a/libsanitizer/asan/asan_interceptors.cpp
>> +++ b/libsanitizer/asan/asan_interceptors.cpp
>> @@ -191,20 +191,11 @@ DECLARE_REAL_AND_INTERCEPTOR(void, free, void *)
>> #include "sanitizer_common/sanitizer_common_syscalls.inc"
>> #include "sanitizer_common/sanitizer_syscalls_netbsd.inc"
>>
>> -struct ThreadStartParam {
>> - atomic_uintptr_t t;
>> - atomic_uintptr_t is_registered;
>> -};
>> -
>> #if ASAN_INTERCEPT_PTHREAD_CREATE
>> static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) {
>> - ThreadStartParam *param = reinterpret_cast<ThreadStartParam *>(arg);
>> - AsanThread *t = nullptr;
>> - while ((t = reinterpret_cast<AsanThread *>(
>> - atomic_load(¶m->t, memory_order_acquire))) == nullptr)
>> - internal_sched_yield();
>> + AsanThread *t = (AsanThread *)arg;
>> SetCurrentThread(t);
>> - return t->ThreadStart(GetTid(), ¶m->is_registered);
>> + return t->ThreadStart(GetTid());
>> }
>>
>> INTERCEPTOR(int, pthread_create, void *thread,
>> @@ -217,9 +208,11 @@ INTERCEPTOR(int, pthread_create, void *thread,
>> int detached = 0;
>> if (attr)
>> REAL(pthread_attr_getdetachstate)(attr, &detached);
>> - ThreadStartParam param;
>> - atomic_store(¶m.t, 0, memory_order_relaxed);
>> - atomic_store(¶m.is_registered, 0, memory_order_relaxed);
>> +
>> + u32 current_tid = GetCurrentTidOrInvalid();
>> + AsanThread *t =
>> + AsanThread::Create(start_routine, arg, current_tid, &stack, detached);
>> +
>> int result;
>> {
>> // Ignore all allocations made by pthread_create: thread stack/TLS may be
>> @@ -229,21 +222,13 @@ INTERCEPTOR(int, pthread_create, void *thread,
>> #if CAN_SANITIZE_LEAKS
>> __lsan::ScopedInterceptorDisabler disabler;
>> #endif
>> - result = REAL(pthread_create)(thread, attr, asan_thread_start, ¶m);
>> + result = REAL(pthread_create)(thread, attr, asan_thread_start, t);
>> }
>> - if (result == 0) {
>> - u32 current_tid = GetCurrentTidOrInvalid();
>> - AsanThread *t =
>> - AsanThread::Create(start_routine, arg, current_tid, &stack, detached);
>> - atomic_store(¶m.t, reinterpret_cast<uptr>(t), memory_order_release);
>> - // Wait until the AsanThread object is initialized and the ThreadRegistry
>> - // entry is in "started" state. One reason for this is that after this
>> - // interceptor exits, the child thread's stack may be the only thing holding
>> - // the |arg| pointer. This may cause LSan to report a leak if leak checking
>> - // happens at a point when the interceptor has already exited, but the stack
>> - // range for the child thread is not yet known.
>> - while (atomic_load(¶m.is_registered, memory_order_acquire) == 0)
>> - internal_sched_yield();
>> + if (result != 0) {
>> + // If the thread didn't start delete the AsanThread to avoid leaking it.
>> + // Note AsanThreadContexts never get destroyed so the AsanThreadContext
>> + // that was just created for the AsanThread is wasted.
>> + t->Destroy();
>> }
>> return result;
>> }
>> diff --git a/libsanitizer/asan/asan_interceptors.h b/libsanitizer/asan/asan_interceptors.h
>> index 56dc34b7d93..e8c58c2dc6b 100644
>> --- a/libsanitizer/asan/asan_interceptors.h
>> +++ b/libsanitizer/asan/asan_interceptors.h
>> @@ -60,7 +60,7 @@ void InitializePlatformInterceptors();
>> # define ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX 0
>> #endif
>>
>> -#if (SANITIZER_LINUX && !SANITIZER_ANDROID) || SANITIZER_SOLARIS
>> +#if SANITIZER_GLIBC || SANITIZER_SOLARIS
>> # define ASAN_INTERCEPT_SWAPCONTEXT 1
>> #else
>> # define ASAN_INTERCEPT_SWAPCONTEXT 0
>> @@ -72,7 +72,7 @@ void InitializePlatformInterceptors();
>> # define ASAN_INTERCEPT_SIGLONGJMP 0
>> #endif
>>
>> -#if SANITIZER_LINUX && !SANITIZER_ANDROID
>> +#if SANITIZER_GLIBC
>> # define ASAN_INTERCEPT___LONGJMP_CHK 1
>> #else
>> # define ASAN_INTERCEPT___LONGJMP_CHK 0
>> @@ -81,12 +81,7 @@ void InitializePlatformInterceptors();
>> #if ASAN_HAS_EXCEPTIONS && !SANITIZER_WINDOWS && !SANITIZER_SOLARIS && \
>> !SANITIZER_NETBSD
>> # define ASAN_INTERCEPT___CXA_THROW 1
>> -# if ! defined(ASAN_HAS_CXA_RETHROW_PRIMARY_EXCEPTION) \
>> - || ASAN_HAS_CXA_RETHROW_PRIMARY_EXCEPTION
>> -# define ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION 1
>> -# else
>> -# define ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION 0
>> -# endif
>> +# define ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION 1
>> # if defined(_GLIBCXX_SJLJ_EXCEPTIONS) || (SANITIZER_IOS && defined(__arm__))
>> # define ASAN_INTERCEPT__UNWIND_SJLJ_RAISEEXCEPTION 1
>> # else
>> @@ -111,7 +106,7 @@ void InitializePlatformInterceptors();
>> # define ASAN_INTERCEPT_ATEXIT 0
>> #endif
>>
>> -#if SANITIZER_LINUX && !SANITIZER_ANDROID
>> +#if SANITIZER_GLIBC
>> # define ASAN_INTERCEPT___STRDUP 1
>> #else
>> # define ASAN_INTERCEPT___STRDUP 0
>> @@ -139,10 +134,10 @@ DECLARE_REAL(uptr, strnlen, const char *s, uptr maxlen)
>> DECLARE_REAL(char*, strstr, const char *s1, const char *s2)
>>
>> #if !SANITIZER_MAC
>> -#define ASAN_INTERCEPT_FUNC(name) \
>> - do { \
>> - if (!INTERCEPT_FUNCTION(name)) \
>> - VReport(1, "AddressSanitizer: failed to intercept '%s'\n'", #name); \
>> +#define ASAN_INTERCEPT_FUNC(name) \
>> + do { \
>> + if (!INTERCEPT_FUNCTION(name)) \
>> + VReport(1, "AddressSanitizer: failed to intercept '%s'\n", #name); \
>> } while (0)
>> #define ASAN_INTERCEPT_FUNC_VER(name, ver) \
>> do { \
>> diff --git a/libsanitizer/asan/asan_linux.cpp b/libsanitizer/asan/asan_linux.cpp
>> index fb1a442b3d4..4bcbe5d02e3 100644
>> --- a/libsanitizer/asan/asan_linux.cpp
>> +++ b/libsanitizer/asan/asan_linux.cpp
>> @@ -55,6 +55,7 @@ extern Elf_Dyn _DYNAMIC;
>> #else
>> #include <sys/ucontext.h>
>> #include <link.h>
>> +extern ElfW(Dyn) _DYNAMIC[];
>> #endif
>>
>> // x86-64 FreeBSD 9.2 and older define 'ucontext_t' incorrectly in
>> @@ -84,7 +85,7 @@ bool IsSystemHeapAddress (uptr addr) { return false; }
>>
>> void *AsanDoesNotSupportStaticLinkage() {
>> // This will fail to link with -static.
>> - return &_DYNAMIC; // defined in link.h
>> + return &_DYNAMIC;
>> }
>>
>> #if ASAN_PREMAP_SHADOW
>> diff --git a/libsanitizer/asan/asan_mapping.h b/libsanitizer/asan/asan_mapping.h
>> index a7136de60d2..455e2364cd0 100644
>> --- a/libsanitizer/asan/asan_mapping.h
>> +++ b/libsanitizer/asan/asan_mapping.h
>> @@ -72,6 +72,13 @@
>> // || `[0x2000000000, 0x23ffffffff]` || LowShadow ||
>> // || `[0x0000000000, 0x1fffffffff]` || LowMem ||
>> //
>> +// Default Linux/RISCV64 Sv39 mapping:
>> +// || `[0x1555550000, 0x3fffffffff]` || HighMem ||
>> +// || `[0x0fffffa000, 0x1555555fff]` || HighShadow ||
>> +// || `[0x0effffa000, 0x0fffff9fff]` || ShadowGap ||
>> +// || `[0x0d55550000, 0x0effff9fff]` || LowShadow ||
>> +// || `[0x0000000000, 0x0d5554ffff]` || LowMem ||
>> +//
>> // Default Linux/AArch64 (39-bit VMA) mapping:
>> // || `[0x2000000000, 0x7fffffffff]` || highmem ||
>> // || `[0x1400000000, 0x1fffffffff]` || highshadow ||
>> @@ -79,20 +86,6 @@
>> // || `[0x1000000000, 0x11ffffffff]` || lowshadow ||
>> // || `[0x0000000000, 0x0fffffffff]` || lowmem ||
>> //
>> -// RISC-V has only 38 bits for task size
>> -// Low mem size is set with kRiscv64_ShadowOffset64 in
>> -// compiler-rt/lib/asan/asan_allocator.h and in
>> -// llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp with
>> -// kRiscv64_ShadowOffset64, High mem top border is set with
>> -// GetMaxVirtualAddress() in
>> -// compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp
>> -// Default Linux/RISCV64 Sv39/Sv48 mapping:
>> -// || `[0x000820000000, 0x003fffffffff]` || HighMem ||
>> -// || `[0x000124000000, 0x00081fffffff]` || HighShadow ||
>> -// || `[0x000024000000, 0x000123ffffff]` || ShadowGap ||
>> -// || `[0x000020000000, 0x000023ffffff]` || LowShadow ||
>> -// || `[0x000000000000, 0x00001fffffff]` || LowMem ||
>> -//
>> // Default Linux/AArch64 (42-bit VMA) mapping:
>> // || `[0x10000000000, 0x3ffffffffff]` || highmem ||
>> // || `[0x0a000000000, 0x0ffffffffff]` || highshadow ||
>> @@ -175,10 +168,10 @@ static const u64 kDefaultShadowOffset64 = 1ULL << 44;
>> static const u64 kDefaultShort64bitShadowOffset =
>> 0x7FFFFFFF & (~0xFFFULL << kDefaultShadowScale); // < 2G.
>> static const u64 kAArch64_ShadowOffset64 = 1ULL << 36;
>> -static const u64 kRiscv64_ShadowOffset64 = 0x20000000;
>> +static const u64 kRiscv64_ShadowOffset64 = 0xd55550000;
>> static const u64 kMIPS32_ShadowOffset32 = 0x0aaa0000;
>> static const u64 kMIPS64_ShadowOffset64 = 1ULL << 37;
>> -static const u64 kPPC64_ShadowOffset64 = 1ULL << 41;
>> +static const u64 kPPC64_ShadowOffset64 = 1ULL << 44;
>> static const u64 kSystemZ_ShadowOffset64 = 1ULL << 52;
>> static const u64 kSPARC64_ShadowOffset64 = 1ULL << 43; // 0x80000000000
>> static const u64 kFreeBSD_ShadowOffset32 = 1ULL << 30; // 0x40000000
>> diff --git a/libsanitizer/asan/asan_new_delete.cpp b/libsanitizer/asan/asan_new_delete.cpp
>> index 5dfcc00fd5d..92a8648452b 100644
>> --- a/libsanitizer/asan/asan_new_delete.cpp
>> +++ b/libsanitizer/asan/asan_new_delete.cpp
>> @@ -45,7 +45,7 @@ COMMENT_EXPORT("??_V@YAXPAX@Z") // operator delete[]
>> #endif
>> #undef COMMENT_EXPORT
>> #else
>> -#define CXX_OPERATOR_ATTRIBUTE INTERCEPTOR_ATTRIBUTE
>> +#define CXX_OPERATOR_ATTRIBUTE INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
>> #endif
>>
>> using namespace __asan;
>> diff --git a/libsanitizer/asan/asan_poisoning.cpp b/libsanitizer/asan/asan_poisoning.cpp
>> index 44f872ef619..fa149ecfde6 100644
>> --- a/libsanitizer/asan/asan_poisoning.cpp
>> +++ b/libsanitizer/asan/asan_poisoning.cpp
>> @@ -364,7 +364,7 @@ void __sanitizer_annotate_contiguous_container(const void *beg_p,
>> &stack);
>> }
>> CHECK_LE(end - beg,
>> - FIRST_32_SECOND_64(1UL << 30, 1ULL << 34)); // Sanity check.
>> + FIRST_32_SECOND_64(1UL << 30, 1ULL << 40)); // Sanity check.
>>
>> uptr a = RoundDownTo(Min(old_mid, new_mid), granularity);
>> uptr c = RoundUpTo(Max(old_mid, new_mid), granularity);
>> diff --git a/libsanitizer/asan/asan_posix.cpp b/libsanitizer/asan/asan_posix.cpp
>> index d7f19d84654..63ad735f8bb 100644
>> --- a/libsanitizer/asan/asan_posix.cpp
>> +++ b/libsanitizer/asan/asan_posix.cpp
>> @@ -56,7 +56,7 @@ bool PlatformUnpoisonStacks() {
>> if (signal_stack.ss_flags != SS_ONSTACK)
>> return false;
>>
>> - // Since we're on the signal altnerate stack, we cannot find the DEFAULT
>> + // Since we're on the signal alternate stack, we cannot find the DEFAULT
>> // stack bottom using a local variable.
>> uptr default_bottom, tls_addr, tls_size, stack_size;
>> GetThreadStackAndTls(/*main=*/false, &default_bottom, &stack_size, &tls_addr,
>> diff --git a/libsanitizer/asan/asan_rtl.cpp b/libsanitizer/asan/asan_rtl.cpp
>> index 7b5a929963c..e715d774228 100644
>> --- a/libsanitizer/asan/asan_rtl.cpp
>> +++ b/libsanitizer/asan/asan_rtl.cpp
>> @@ -62,19 +62,9 @@ static void AsanDie() {
>> }
>> }
>>
>> -static void AsanCheckFailed(const char *file, int line, const char *cond,
>> - u64 v1, u64 v2) {
>> - Report("AddressSanitizer CHECK failed: %s:%d \"%s\" (0x%zx, 0x%zx)\n", file,
>> - line, cond, (uptr)v1, (uptr)v2);
>> -
>> - // Print a stack trace the first time we come here. Otherwise, we probably
>> - // failed a CHECK during symbolization.
>> - static atomic_uint32_t num_calls;
>> - if (atomic_fetch_add(&num_calls, 1, memory_order_relaxed) == 0) {
>> - PRINT_CURRENT_STACK_CHECK();
>> - }
>> -
>> - Die();
>> +static void CheckUnwind() {
>> + GET_STACK_TRACE(kStackTraceMax, common_flags()->fast_unwind_on_check);
>> + stack.Print();
>> }
>>
>> // -------------------------- Globals --------------------- {{{1
>> @@ -432,7 +422,7 @@ static void AsanInitInternal() {
>>
>> // Install tool-specific callbacks in sanitizer_common.
>> AddDieCallback(AsanDie);
>> - SetCheckFailedCallback(AsanCheckFailed);
>> + SetCheckUnwindCallback(CheckUnwind);
>> SetPrintfAndReportCallback(AppendToErrorMessageBuffer);
>>
>> __sanitizer_set_report_path(common_flags()->log_path);
>> @@ -568,7 +558,7 @@ void UnpoisonStack(uptr bottom, uptr top, const char *type) {
>> type, top, bottom, top - bottom, top - bottom);
>> return;
>> }
>> - PoisonShadow(bottom, top - bottom, 0);
>> + PoisonShadow(bottom, RoundUpTo(top - bottom, SHADOW_GRANULARITY), 0);
>> }
>>
>> static void UnpoisonDefaultStack() {
>> diff --git a/libsanitizer/asan/asan_stack.h b/libsanitizer/asan/asan_stack.h
>> index 47ca85a1644..b9575d2f427 100644
>> --- a/libsanitizer/asan/asan_stack.h
>> +++ b/libsanitizer/asan/asan_stack.h
>> @@ -54,9 +54,6 @@ u32 GetMallocContextSize();
>> #define GET_STACK_TRACE_FATAL_HERE \
>> GET_STACK_TRACE(kStackTraceMax, common_flags()->fast_unwind_on_fatal)
>>
>> -#define GET_STACK_TRACE_CHECK_HERE \
>> - GET_STACK_TRACE(kStackTraceMax, common_flags()->fast_unwind_on_check)
>> -
>> #define GET_STACK_TRACE_THREAD \
>> GET_STACK_TRACE(kStackTraceMax, true)
>>
>> @@ -71,10 +68,4 @@ u32 GetMallocContextSize();
>> stack.Print(); \
>> }
>>
>> -#define PRINT_CURRENT_STACK_CHECK() \
>> - { \
>> - GET_STACK_TRACE_CHECK_HERE; \
>> - stack.Print(); \
>> - }
>> -
>> #endif // ASAN_STACK_H
>> diff --git a/libsanitizer/asan/asan_thread.cpp b/libsanitizer/asan/asan_thread.cpp
>> index fb09af0ecca..9c3c86f5735 100644
>> --- a/libsanitizer/asan/asan_thread.cpp
>> +++ b/libsanitizer/asan/asan_thread.cpp
>> @@ -100,18 +100,27 @@ void AsanThread::Destroy() {
>> int tid = this->tid();
>> VReport(1, "T%d exited\n", tid);
>>
>> - malloc_storage().CommitBack();
>> - if (common_flags()->use_sigaltstack) UnsetAlternateSignalStack();
>> - asanThreadRegistry().FinishThread(tid);
>> - FlushToDeadThreadStats(&stats_);
>> - // We also clear the shadow on thread destruction because
>> - // some code may still be executing in later TSD destructors
>> - // and we don't want it to have any poisoned stack.
>> - ClearShadowForThreadStackAndTLS();
>> - DeleteFakeStack(tid);
>> + bool was_running =
>> + (asanThreadRegistry().FinishThread(tid) == ThreadStatusRunning);
>> + if (was_running) {
>> + if (AsanThread *thread = GetCurrentThread())
>> + CHECK_EQ(this, thread);
>> + malloc_storage().CommitBack();
>> + if (common_flags()->use_sigaltstack)
>> + UnsetAlternateSignalStack();
>> + FlushToDeadThreadStats(&stats_);
>> + // We also clear the shadow on thread destruction because
>> + // some code may still be executing in later TSD destructors
>> + // and we don't want it to have any poisoned stack.
>> + ClearShadowForThreadStackAndTLS();
>> + DeleteFakeStack(tid);
>> + } else {
>> + CHECK_NE(this, GetCurrentThread());
>> + }
>> uptr size = RoundUpTo(sizeof(AsanThread), GetPageSizeCached());
>> UnmapOrDie(this, size);
>> - DTLS_Destroy();
>> + if (was_running)
>> + DTLS_Destroy();
>> }
>>
>> void AsanThread::StartSwitchFiber(FakeStack **fake_stack_save, uptr bottom,
>> @@ -219,7 +228,7 @@ FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() {
>> }
>>
>> void AsanThread::Init(const InitOptions *options) {
>> - DCHECK_NE(tid(), ThreadRegistry::kUnknownTid);
>> + DCHECK_NE(tid(), kInvalidTid);
>> next_stack_top_ = next_stack_bottom_ = 0;
>> atomic_store(&stack_switching_, false, memory_order_release);
>> CHECK_EQ(this->stack_size(), 0U);
>> @@ -253,12 +262,9 @@ void AsanThread::Init(const InitOptions *options) {
>> // SetThreadStackAndTls.
>> #if !SANITIZER_FUCHSIA && !SANITIZER_RTEMS
>>
>> -thread_return_t AsanThread::ThreadStart(
>> - tid_t os_id, atomic_uintptr_t *signal_thread_is_registered) {
>> +thread_return_t AsanThread::ThreadStart(tid_t os_id) {
>> Init();
>> asanThreadRegistry().StartThread(tid(), os_id, ThreadType::Regular, nullptr);
>> - if (signal_thread_is_registered)
>> - atomic_store(signal_thread_is_registered, 1, memory_order_release);
>>
>> if (common_flags()->use_sigaltstack) SetAlternateSignalStack();
>>
>> @@ -285,11 +291,10 @@ thread_return_t AsanThread::ThreadStart(
>>
>> AsanThread *CreateMainThread() {
>> AsanThread *main_thread = AsanThread::Create(
>> - /* start_routine */ nullptr, /* arg */ nullptr, /* parent_tid */ 0,
>> + /* start_routine */ nullptr, /* arg */ nullptr, /* parent_tid */ kMainTid,
>> /* stack */ nullptr, /* detached */ true);
>> SetCurrentThread(main_thread);
>> - main_thread->ThreadStart(internal_getpid(),
>> - /* signal_thread_is_registered */ nullptr);
>> + main_thread->ThreadStart(internal_getpid());
>> return main_thread;
>> }
>>
>> @@ -300,9 +305,9 @@ void AsanThread::SetThreadStackAndTls(const InitOptions *options) {
>> DCHECK_EQ(options, nullptr);
>> uptr tls_size = 0;
>> uptr stack_size = 0;
>> - GetThreadStackAndTls(tid() == 0, &stack_bottom_, &stack_size, &tls_begin_,
>> - &tls_size);
>> - stack_top_ = stack_bottom_ + stack_size;
>> + GetThreadStackAndTls(tid() == kMainTid, &stack_bottom_, &stack_size,
>> + &tls_begin_, &tls_size);
>> + stack_top_ = RoundDownTo(stack_bottom_ + stack_size, SHADOW_GRANULARITY);
>> tls_end_ = tls_begin_ + tls_size;
>> dtls_ = DTLS_Get();
>>
>> @@ -426,7 +431,7 @@ AsanThread *GetCurrentThread() {
>> // address. We are not entirely sure that we have correct main thread
>> // limits, so only do this magic on Android, and only if the found thread
>> // is the main thread.
>> - AsanThreadContext *tctx = GetThreadContextByTidLocked(0);
>> + AsanThreadContext *tctx = GetThreadContextByTidLocked(kMainTid);
>> if (tctx && ThreadStackContainsAddress(tctx, &context)) {
>> SetCurrentThread(tctx->thread);
>> return tctx->thread;
>> @@ -463,7 +468,7 @@ AsanThread *FindThreadByStackAddress(uptr addr) {
>> void EnsureMainThreadIDIsCorrect() {
>> AsanThreadContext *context =
>> reinterpret_cast<AsanThreadContext *>(AsanTSDGet());
>> - if (context && (context->tid == 0))
>> + if (context && (context->tid == kMainTid))
>> context->os_id = GetTid();
>> }
>>
>> diff --git a/libsanitizer/asan/asan_thread.h b/libsanitizer/asan/asan_thread.h
>> index ea58de4216a..200069ce0dd 100644
>> --- a/libsanitizer/asan/asan_thread.h
>> +++ b/libsanitizer/asan/asan_thread.h
>> @@ -28,7 +28,6 @@ struct DTLS;
>>
>> namespace __asan {
>>
>> -const u32 kInvalidTid = 0xffffff; // Must fit into 24 bits.
>> const u32 kMaxNumberOfThreads = (1 << 22); // 4M
>>
>> class AsanThread;
>> @@ -69,8 +68,7 @@ class AsanThread {
>> struct InitOptions;
>> void Init(const InitOptions *options = nullptr);
>>
>> - thread_return_t ThreadStart(tid_t os_id,
>> - atomic_uintptr_t *signal_thread_is_registered);
>> + thread_return_t ThreadStart(tid_t os_id);
>>
>> uptr stack_top();
>> uptr stack_bottom();
>> @@ -132,6 +130,8 @@ class AsanThread {
>>
>> void *extra_spill_area() { return &extra_spill_area_; }
>>
>> + void *get_arg() { return arg_; }
>> +
>> private:
>> // NOTE: There is no AsanThread constructor. It is allocated
>> // via mmap() and *must* be valid in zero-initialized state.
>> diff --git a/libsanitizer/asan/asan_win.cpp b/libsanitizer/asan/asan_win.cpp
>> index 8044ae16ff9..1577c83cf99 100644
>> --- a/libsanitizer/asan/asan_win.cpp
>> +++ b/libsanitizer/asan/asan_win.cpp
>> @@ -134,7 +134,7 @@ INTERCEPTOR(int, _except_handler4, void *a, void *b, void *c, void *d) {
>> static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) {
>> AsanThread *t = (AsanThread *)arg;
>> SetCurrentThread(t);
>> - return t->ThreadStart(GetTid(), /* signal_thread_is_registered */ nullptr);
>> + return t->ThreadStart(GetTid());
>> }
>>
>> INTERCEPTOR_WINAPI(HANDLE, CreateThread, LPSECURITY_ATTRIBUTES security,
>> diff --git a/libsanitizer/builtins/assembly.h b/libsanitizer/builtins/assembly.h
>> index f437cb87f60..9c015059af5 100644
>> --- a/libsanitizer/builtins/assembly.h
>> +++ b/libsanitizer/builtins/assembly.h
>> @@ -14,8 +14,8 @@
>> #ifndef COMPILERRT_ASSEMBLY_H
>> #define COMPILERRT_ASSEMBLY_H
>>
>> -#if defined(__POWERPC__) || defined(__powerpc__) || defined(__ppc__)
>> -#define SEPARATOR @
>> +#if defined(__APPLE__) && defined(__aarch64__)
>> +#define SEPARATOR %%
>> #else
>> #define SEPARATOR ;
>> #endif
>> @@ -35,14 +35,14 @@
>> #define HIDDEN(name) .hidden name
>> #define LOCAL_LABEL(name) .L_##name
>> #define FILE_LEVEL_DIRECTIVE
>> -#if defined(__arm__)
>> +#if defined(__arm__) || defined(__aarch64__)
>> #define SYMBOL_IS_FUNC(name) .type name,%function
>> #else
>> #define SYMBOL_IS_FUNC(name) .type name,@function
>> #endif
>> #define CONST_SECTION .section .rodata
>>
>> -#if defined(__GNU__) || defined(__FreeBSD__) || defined(__Fuchsia__) || \
>> +#if defined(__GNU__) || defined(__FreeBSD__) || defined(__Fuchsia__) || \
>> defined(__linux__)
>> #define NO_EXEC_STACK_DIRECTIVE .section .note.GNU-stack,"",%progbits
>> #else
>> @@ -65,6 +65,68 @@
>>
>> #endif
>>
>> +#if defined(__arm__) || defined(__aarch64__)
>> +#define FUNC_ALIGN \
>> + .text SEPARATOR \
>> + .balign 16 SEPARATOR
>> +#else
>> +#define FUNC_ALIGN
>> +#endif
>> +
>> +// BTI and PAC gnu property note
>> +#define NT_GNU_PROPERTY_TYPE_0 5
>> +#define GNU_PROPERTY_AARCH64_FEATURE_1_AND 0xc0000000
>> +#define GNU_PROPERTY_AARCH64_FEATURE_1_BTI 1
>> +#define GNU_PROPERTY_AARCH64_FEATURE_1_PAC 2
>> +
>> +#if defined(__ARM_FEATURE_BTI_DEFAULT)
>> +#define BTI_FLAG GNU_PROPERTY_AARCH64_FEATURE_1_BTI
>> +#else
>> +#define BTI_FLAG 0
>> +#endif
>> +
>> +#if __ARM_FEATURE_PAC_DEFAULT & 3
>> +#define PAC_FLAG GNU_PROPERTY_AARCH64_FEATURE_1_PAC
>> +#else
>> +#define PAC_FLAG 0
>> +#endif
>> +
>> +#define GNU_PROPERTY(type, value) \
>> + .pushsection .note.gnu.property, "a" SEPARATOR \
>> + .p2align 3 SEPARATOR \
>> + .word 4 SEPARATOR \
>> + .word 16 SEPARATOR \
>> + .word NT_GNU_PROPERTY_TYPE_0 SEPARATOR \
>> + .asciz "GNU" SEPARATOR \
>> + .word type SEPARATOR \
>> + .word 4 SEPARATOR \
>> + .word value SEPARATOR \
>> + .word 0 SEPARATOR \
>> + .popsection
>> +
>> +#if BTI_FLAG != 0
>> +#define BTI_C hint #34
>> +#define BTI_J hint #36
>> +#else
>> +#define BTI_C
>> +#define BTI_J
>> +#endif
>> +
>> +#if (BTI_FLAG | PAC_FLAG) != 0
>> +#define GNU_PROPERTY_BTI_PAC \
>> + GNU_PROPERTY(GNU_PROPERTY_AARCH64_FEATURE_1_AND, BTI_FLAG | PAC_FLAG)
>> +#else
>> +#define GNU_PROPERTY_BTI_PAC
>> +#endif
>> +
>> +#if defined(__clang__) || defined(__GCC_HAVE_DWARF2_CFI_ASM)
>> +#define CFI_START .cfi_startproc
>> +#define CFI_END .cfi_endproc
>> +#else
>> +#define CFI_START
>> +#define CFI_END
>> +#endif
>> +
>> #if defined(__arm__)
>>
>> // Determine actual [ARM][THUMB[1][2]] ISA using compiler predefined macros:
>> @@ -131,15 +193,24 @@
>> #define DEFINE_CODE_STATE
>> #endif
>>
>> -#define GLUE2(a, b) a##b
>> -#define GLUE(a, b) GLUE2(a, b)
>> +#define GLUE2_(a, b) a##b
>> +#define GLUE(a, b) GLUE2_(a, b)
>> +#define GLUE2(a, b) GLUE2_(a, b)
>> +#define GLUE3_(a, b, c) a##b##c
>> +#define GLUE3(a, b, c) GLUE3_(a, b, c)
>> +#define GLUE4_(a, b, c, d) a##b##c##d
>> +#define GLUE4(a, b, c, d) GLUE4_(a, b, c, d)
>> +
>> #define SYMBOL_NAME(name) GLUE(__USER_LABEL_PREFIX__, name)
>>
>> #ifdef VISIBILITY_HIDDEN
>> #define DECLARE_SYMBOL_VISIBILITY(name) \
>> HIDDEN(SYMBOL_NAME(name)) SEPARATOR
>> +#define DECLARE_SYMBOL_VISIBILITY_UNMANGLED(name) \
>> + HIDDEN(name) SEPARATOR
>> #else
>> #define DECLARE_SYMBOL_VISIBILITY(name)
>> +#define DECLARE_SYMBOL_VISIBILITY_UNMANGLED(name)
>> #endif
>>
>> #define DEFINE_COMPILERRT_FUNCTION(name) \
>> @@ -177,6 +248,16 @@
>> DECLARE_FUNC_ENCODING \
>> name:
>>
>> +#define DEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(name) \
>> + DEFINE_CODE_STATE \
>> + FUNC_ALIGN \
>> + .globl name SEPARATOR \
>> + SYMBOL_IS_FUNC(name) SEPARATOR \
>> + DECLARE_SYMBOL_VISIBILITY_UNMANGLED(name) SEPARATOR \
>> + CFI_START SEPARATOR \
>> + DECLARE_FUNC_ENCODING \
>> + name: SEPARATOR BTI_C
>> +
>> #define DEFINE_COMPILERRT_FUNCTION_ALIAS(name, target) \
>> .globl SYMBOL_NAME(name) SEPARATOR \
>> SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \
>> @@ -193,8 +274,13 @@
>> #ifdef __ELF__
>> #define END_COMPILERRT_FUNCTION(name) \
>> .size SYMBOL_NAME(name), . - SYMBOL_NAME(name)
>> +#define END_COMPILERRT_OUTLINE_FUNCTION(name) \
>> + CFI_END SEPARATOR \
>> + .size SYMBOL_NAME(name), . - SYMBOL_NAME(name)
>> #else
>> #define END_COMPILERRT_FUNCTION(name)
>> +#define END_COMPILERRT_OUTLINE_FUNCTION(name) \
>> + CFI_END
>> #endif
>>
>> #endif // COMPILERRT_ASSEMBLY_H
>> diff --git a/libsanitizer/hwasan/hwasan.cpp b/libsanitizer/hwasan/hwasan.cpp
>> index c5322110cb6..8d6c25261b8 100644
>> --- a/libsanitizer/hwasan/hwasan.cpp
>> +++ b/libsanitizer/hwasan/hwasan.cpp
>> @@ -128,16 +128,11 @@ static void InitializeFlags() {
>> if (common_flags()->help) parser.PrintFlagDescriptions();
>> }
>>
>> -static void HWAsanCheckFailed(const char *file, int line, const char *cond,
>> - u64 v1, u64 v2) {
>> - Report("HWAddressSanitizer CHECK failed: %s:%d \"%s\" (0x%zx, 0x%zx)\n", file,
>> - line, cond, (uptr)v1, (uptr)v2);
>> - PRINT_CURRENT_STACK_CHECK();
>> - Die();
>> +static void CheckUnwind() {
>> + GET_FATAL_STACK_TRACE_PC_BP(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME());
>> + stack.Print();
>> }
>>
>> -static constexpr uptr kMemoryUsageBufferSize = 4096;
>> -
>> static void HwasanFormatMemoryUsage(InternalScopedString &s) {
>> HwasanThreadList &thread_list = hwasanThreadList();
>> auto thread_stats = thread_list.GetThreadStats();
>> @@ -155,6 +150,8 @@ static void HwasanFormatMemoryUsage(InternalScopedString &s) {
>> }
>>
>> #if SANITIZER_ANDROID
>> +static constexpr uptr kMemoryUsageBufferSize = 4096;
>> +
>> static char *memory_usage_buffer = nullptr;
>>
>> static void InitMemoryUsage() {
>> @@ -171,7 +168,7 @@ void UpdateMemoryUsage() {
>> return;
>> if (!memory_usage_buffer)
>> InitMemoryUsage();
>> - InternalScopedString s(kMemoryUsageBufferSize);
>> + InternalScopedString s;
>> HwasanFormatMemoryUsage(s);
>> internal_strncpy(memory_usage_buffer, s.data(), kMemoryUsageBufferSize - 1);
>> memory_usage_buffer[kMemoryUsageBufferSize - 1] = '\0';
>> @@ -271,7 +268,7 @@ void __hwasan_init() {
>> InitializeFlags();
>>
>> // Install tool-specific callbacks in sanitizer_common.
>> - SetCheckFailedCallback(HWAsanCheckFailed);
>> + SetCheckUnwindCallback(CheckUnwind);
>>
>> __sanitizer_set_report_path(common_flags()->log_path);
>>
>> @@ -493,7 +490,7 @@ extern "C" void *__hwasan_extra_spill_area() {
>> }
>>
>> void __hwasan_print_memory_usage() {
>> - InternalScopedString s(kMemoryUsageBufferSize);
>> + InternalScopedString s;
>> HwasanFormatMemoryUsage(s);
>> Printf("%s\n", s.data());
>> }
>> diff --git a/libsanitizer/hwasan/hwasan.h b/libsanitizer/hwasan/hwasan.h
>> index d4521efd089..8515df559f3 100644
>> --- a/libsanitizer/hwasan/hwasan.h
>> +++ b/libsanitizer/hwasan/hwasan.h
>> @@ -14,11 +14,12 @@
>> #ifndef HWASAN_H
>> #define HWASAN_H
>>
>> +#include "hwasan_flags.h"
>> +#include "hwasan_interface_internal.h"
>> +#include "sanitizer_common/sanitizer_common.h"
>> #include "sanitizer_common/sanitizer_flags.h"
>> #include "sanitizer_common/sanitizer_internal_defs.h"
>> #include "sanitizer_common/sanitizer_stacktrace.h"
>> -#include "hwasan_interface_internal.h"
>> -#include "hwasan_flags.h"
>> #include "ubsan/ubsan_platform.h"
>>
>> #ifndef HWASAN_CONTAINS_UBSAN
>> @@ -35,10 +36,31 @@
>>
>> typedef u8 tag_t;
>>
>> +#if defined(__x86_64__)
>> +// Tags are done in middle bits using userspace aliasing.
>> +constexpr unsigned kAddressTagShift = 39;
>> +constexpr unsigned kTagBits = 3;
>> +
>> +// The alias region is placed next to the shadow so the upper bits of all
>> +// taggable addresses matches the upper bits of the shadow base. This shift
>> +// value determines which upper bits must match. It has a floor of 44 since the
>> +// shadow is always 8TB.
>> +// TODO(morehouse): In alias mode we can shrink the shadow and use a
>> +// simpler/faster shadow calculation.
>> +constexpr unsigned kTaggableRegionCheckShift =
>> + __sanitizer::Max(kAddressTagShift + kTagBits + 1U, 44U);
>> +#else
>> // TBI (Top Byte Ignore) feature of AArch64: bits [63:56] are ignored in address
>> // translation and can be used to store a tag.
>> -const unsigned kAddressTagShift = 56;
>> -const uptr kAddressTagMask = 0xFFUL << kAddressTagShift;
>> +constexpr unsigned kAddressTagShift = 56;
>> +constexpr unsigned kTagBits = 8;
>> +#endif // defined(__x86_64__)
>> +
>> +// Mask for extracting tag bits from the lower 8 bits.
>> +constexpr uptr kTagMask = (1UL << kTagBits) - 1;
>> +
>> +// Mask for extracting tag bits from full pointers.
>> +constexpr uptr kAddressTagMask = kTagMask << kAddressTagShift;
>>
>> // Minimal alignment of the shadow base address. Determines the space available
>> // for threads and stack histories. This is an ABI constant.
>> @@ -50,7 +72,7 @@ const unsigned kRecordFPLShift = 4;
>> const unsigned kRecordFPModulus = 1 << (64 - kRecordFPShift + kRecordFPLShift);
>>
>> static inline tag_t GetTagFromPointer(uptr p) {
>> - return p >> kAddressTagShift;
>> + return (p >> kAddressTagShift) & kTagMask;
>> }
>>
>> static inline uptr UntagAddr(uptr tagged_addr) {
>> @@ -105,15 +127,6 @@ void InstallAtExitHandler();
>> if (hwasan_inited) \
>> stack.Unwind(pc, bp, nullptr, common_flags()->fast_unwind_on_fatal)
>>
>> -#define GET_FATAL_STACK_TRACE_HERE \
>> - GET_FATAL_STACK_TRACE_PC_BP(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME())
>> -
>> -#define PRINT_CURRENT_STACK_CHECK() \
>> - { \
>> - GET_FATAL_STACK_TRACE_HERE; \
>> - stack.Print(); \
>> - }
>> -
>> void HwasanTSDInit();
>> void HwasanTSDThreadInit();
>>
>> diff --git a/libsanitizer/hwasan/hwasan_allocator.cpp b/libsanitizer/hwasan/hwasan_allocator.cpp
>> index 0b6b7347892..a6fc794082a 100644
>> --- a/libsanitizer/hwasan/hwasan_allocator.cpp
>> +++ b/libsanitizer/hwasan/hwasan_allocator.cpp
>> @@ -29,8 +29,8 @@ static AllocatorCache fallback_allocator_cache;
>> static SpinMutex fallback_mutex;
>> static atomic_uint8_t hwasan_allocator_tagging_enabled;
>>
>> -static const tag_t kFallbackAllocTag = 0xBB;
>> -static const tag_t kFallbackFreeTag = 0xBC;
>> +static constexpr tag_t kFallbackAllocTag = 0xBB & kTagMask;
>> +static constexpr tag_t kFallbackFreeTag = 0xBC;
>>
>> enum RightAlignMode {
>> kRightAlignNever,
>> @@ -84,7 +84,8 @@ void HwasanAllocatorInit() {
>> atomic_store_relaxed(&hwasan_allocator_tagging_enabled,
>> !flags()->disable_allocator_tagging);
>> SetAllocatorMayReturnNull(common_flags()->allocator_may_return_null);
>> - allocator.Init(common_flags()->allocator_release_to_os_interval_ms);
>> + allocator.Init(common_flags()->allocator_release_to_os_interval_ms,
>> + kAliasRegionStart);
>> for (uptr i = 0; i < sizeof(tail_magic); i++)
>> tail_magic[i] = GetCurrentThread()->GenerateRandomTag();
>> }
>> @@ -148,7 +149,8 @@ static void *HwasanAllocate(StackTrace *stack, uptr orig_size, uptr alignment,
>> // Tagging can only be skipped when both tag_in_malloc and tag_in_free are
>> // false. When tag_in_malloc = false and tag_in_free = true malloc needs to
>> // retag to 0.
>> - if ((flags()->tag_in_malloc || flags()->tag_in_free) &&
>> + if (InTaggableRegion(reinterpret_cast<uptr>(user_ptr)) &&
>> + (flags()->tag_in_malloc || flags()->tag_in_free) &&
>> atomic_load_relaxed(&hwasan_allocator_tagging_enabled)) {
>> if (flags()->tag_in_malloc && malloc_bisect(stack, orig_size)) {
>> tag_t tag = t ? t->GenerateRandomTag() : kFallbackAllocTag;
>> @@ -175,6 +177,8 @@ static void *HwasanAllocate(StackTrace *stack, uptr orig_size, uptr alignment,
>> static bool PointerAndMemoryTagsMatch(void *tagged_ptr) {
>> CHECK(tagged_ptr);
>> uptr tagged_uptr = reinterpret_cast<uptr>(tagged_ptr);
>> + if (!InTaggableRegion(tagged_uptr))
>> + return true;
>> tag_t mem_tag = *reinterpret_cast<tag_t *>(
>> MemToShadow(reinterpret_cast<uptr>(UntagPtr(tagged_ptr))));
>> return PossiblyShortTagMatches(mem_tag, tagged_uptr, 1);
>> @@ -187,7 +191,9 @@ static void HwasanDeallocate(StackTrace *stack, void *tagged_ptr) {
>> if (!PointerAndMemoryTagsMatch(tagged_ptr))
>> ReportInvalidFree(stack, reinterpret_cast<uptr>(tagged_ptr));
>>
>> - void *untagged_ptr = UntagPtr(tagged_ptr);
>> + void *untagged_ptr = InTaggableRegion(reinterpret_cast<uptr>(tagged_ptr))
>> + ? UntagPtr(tagged_ptr)
>> + : tagged_ptr;
>> void *aligned_ptr = reinterpret_cast<void *>(
>> RoundDownTo(reinterpret_cast<uptr>(untagged_ptr), kShadowAlignment));
>> Metadata *meta =
>> @@ -219,10 +225,14 @@ static void HwasanDeallocate(StackTrace *stack, void *tagged_ptr) {
>> Min(TaggedSize(orig_size), (uptr)flags()->max_free_fill_size);
>> internal_memset(aligned_ptr, flags()->free_fill_byte, fill_size);
>> }
>> - if (flags()->tag_in_free && malloc_bisect(stack, 0) &&
>> - atomic_load_relaxed(&hwasan_allocator_tagging_enabled))
>> + if (InTaggableRegion(reinterpret_cast<uptr>(tagged_ptr)) &&
>> + flags()->tag_in_free && malloc_bisect(stack, 0) &&
>> + atomic_load_relaxed(&hwasan_allocator_tagging_enabled)) {
>> + // Always store full 8-bit tags on free to maximize UAF detection.
>> + tag_t tag = t ? t->GenerateRandomTag(/*num_bits=*/8) : kFallbackFreeTag;
>> TagMemoryAligned(reinterpret_cast<uptr>(aligned_ptr), TaggedSize(orig_size),
>> - t ? t->GenerateRandomTag() : kFallbackFreeTag);
>> + tag);
>> + }
>> if (t) {
>> allocator.Deallocate(t->allocator_cache(), aligned_ptr);
>> if (auto *ha = t->heap_allocations())
>> @@ -365,7 +375,7 @@ int hwasan_posix_memalign(void **memptr, uptr alignment, uptr size,
>> // OOM error is already taken care of by HwasanAllocate.
>> return errno_ENOMEM;
>> CHECK(IsAligned((uptr)ptr, alignment));
>> - *(void **)UntagPtr(memptr) = ptr;
>> + *memptr = ptr;
>> return 0;
>> }
>>
>> diff --git a/libsanitizer/hwasan/hwasan_allocator.h b/libsanitizer/hwasan/hwasan_allocator.h
>> index 43670a6a3fb..03bbcff3f0f 100644
>> --- a/libsanitizer/hwasan/hwasan_allocator.h
>> +++ b/libsanitizer/hwasan/hwasan_allocator.h
>> @@ -13,13 +13,15 @@
>> #ifndef HWASAN_ALLOCATOR_H
>> #define HWASAN_ALLOCATOR_H
>>
>> +#include "hwasan.h"
>> +#include "hwasan_interface_internal.h"
>> +#include "hwasan_poisoning.h"
>> #include "sanitizer_common/sanitizer_allocator.h"
>> #include "sanitizer_common/sanitizer_allocator_checks.h"
>> #include "sanitizer_common/sanitizer_allocator_interface.h"
>> #include "sanitizer_common/sanitizer_allocator_report.h"
>> #include "sanitizer_common/sanitizer_common.h"
>> #include "sanitizer_common/sanitizer_ring_buffer.h"
>> -#include "hwasan_poisoning.h"
>>
>> #if !defined(__aarch64__) && !defined(__x86_64__)
>> #error Unsupported platform
>> @@ -55,7 +57,12 @@ static const uptr kMaxAllowedMallocSize = 1UL << 40; // 1T
>>
>> struct AP64 {
>> static const uptr kSpaceBeg = ~0ULL;
>> +
>> +#if defined(__x86_64__)
>> + static const uptr kSpaceSize = 1ULL << kAddressTagShift;
>> +#else
>> static const uptr kSpaceSize = 0x2000000000ULL;
>> +#endif
>> static const uptr kMetadataSize = sizeof(Metadata);
>> typedef __sanitizer::VeryDenseSizeClassMap SizeClassMap;
>> using AddressSpaceView = LocalAddressSpaceView;
>> @@ -102,6 +109,16 @@ typedef RingBuffer<HeapAllocationRecord> HeapAllocationsRingBuffer;
>>
>> void GetAllocatorStats(AllocatorStatCounters s);
>>
>> +inline bool InTaggableRegion(uptr addr) {
>> +#if defined(__x86_64__)
>> + // Aliases are mapped next to shadow so that the upper bits match the shadow
>> + // base.
>> + return (addr >> kTaggableRegionCheckShift) ==
>> + (__hwasan_shadow_memory_dynamic_address >> kTaggableRegionCheckShift);
>> +#endif
>> + return true;
>> +}
>> +
>> } // namespace __hwasan
>>
>> #endif // HWASAN_ALLOCATOR_H
>> diff --git a/libsanitizer/hwasan/hwasan_checks.h b/libsanitizer/hwasan/hwasan_checks.h
>> index a8de0fef20f..ab543ea88be 100644
>> --- a/libsanitizer/hwasan/hwasan_checks.h
>> +++ b/libsanitizer/hwasan/hwasan_checks.h
>> @@ -13,6 +13,7 @@
>> #ifndef HWASAN_CHECKS_H
>> #define HWASAN_CHECKS_H
>>
>> +#include "hwasan_allocator.h"
>> #include "hwasan_mapping.h"
>> #include "sanitizer_common/sanitizer_common.h"
>>
>> @@ -81,6 +82,8 @@ enum class AccessType { Load, Store };
>>
>> template <ErrorAction EA, AccessType AT, unsigned LogSize>
>> __attribute__((always_inline, nodebug)) static void CheckAddress(uptr p) {
>> + if (!InTaggableRegion(p))
>> + return;
>> uptr ptr_raw = p & ~kAddressTagMask;
>> tag_t mem_tag = *(tag_t *)MemToShadow(ptr_raw);
>> if (UNLIKELY(!PossiblyShortTagMatches(mem_tag, p, 1 << LogSize))) {
>> @@ -94,7 +97,7 @@ __attribute__((always_inline, nodebug)) static void CheckAddress(uptr p) {
>> template <ErrorAction EA, AccessType AT>
>> __attribute__((always_inline, nodebug)) static void CheckAddressSized(uptr p,
>> uptr sz) {
>> - if (sz == 0)
>> + if (sz == 0 || !InTaggableRegion(p))
>> return;
>> tag_t ptr_tag = GetTagFromPointer(p);
>> uptr ptr_raw = p & ~kAddressTagMask;
>> diff --git a/libsanitizer/hwasan/hwasan_dynamic_shadow.cpp b/libsanitizer/hwasan/hwasan_dynamic_shadow.cpp
>> index 12730b29bae..f53276e330d 100644
>> --- a/libsanitizer/hwasan/hwasan_dynamic_shadow.cpp
>> +++ b/libsanitizer/hwasan/hwasan_dynamic_shadow.cpp
>> @@ -12,15 +12,17 @@
>> ///
>> //===----------------------------------------------------------------------===//
>>
>> -#include "hwasan.h"
>> #include "hwasan_dynamic_shadow.h"
>> -#include "hwasan_mapping.h"
>> -#include "sanitizer_common/sanitizer_common.h"
>> -#include "sanitizer_common/sanitizer_posix.h"
>>
>> #include <elf.h>
>> #include <link.h>
>>
>> +#include "hwasan.h"
>> +#include "hwasan_mapping.h"
>> +#include "hwasan_thread_list.h"
>> +#include "sanitizer_common/sanitizer_common.h"
>> +#include "sanitizer_common/sanitizer_posix.h"
>> +
>> // The code in this file needs to run in an unrelocated binary. It should not
>> // access any external symbol, including its own non-hidden globals.
>>
>> @@ -117,6 +119,12 @@ namespace __hwasan {
>> void InitShadowGOT() {}
>>
>> uptr FindDynamicShadowStart(uptr shadow_size_bytes) {
>> +#if defined(__x86_64__)
>> + constexpr uptr kAliasSize = 1ULL << kAddressTagShift;
>> + constexpr uptr kNumAliases = 1ULL << kTagBits;
>> + return MapDynamicShadowAndAliases(shadow_size_bytes, kAliasSize, kNumAliases,
>> + RingBufferSize());
>> +#endif
>> return MapDynamicShadow(shadow_size_bytes, kShadowScale, kShadowBaseAlignment,
>> kHighMemEnd);
>> }
>> diff --git a/libsanitizer/hwasan/hwasan_flags.h b/libsanitizer/hwasan/hwasan_flags.h
>> index 0a6998f675d..b17750158d0 100644
>> --- a/libsanitizer/hwasan/hwasan_flags.h
>> +++ b/libsanitizer/hwasan/hwasan_flags.h
>> @@ -12,6 +12,8 @@
>> #ifndef HWASAN_FLAGS_H
>> #define HWASAN_FLAGS_H
>>
>> +#include "sanitizer_common/sanitizer_internal_defs.h"
>> +
>> namespace __hwasan {
>>
>> struct Flags {
>> diff --git a/libsanitizer/hwasan/hwasan_flags.inc b/libsanitizer/hwasan/hwasan_flags.inc
>> index 8e431d9c4ff..18ea47f981b 100644
>> --- a/libsanitizer/hwasan/hwasan_flags.inc
>> +++ b/libsanitizer/hwasan/hwasan_flags.inc
>> @@ -72,3 +72,12 @@ HWASAN_FLAG(uptr, malloc_bisect_right, 0,
>> HWASAN_FLAG(bool, malloc_bisect_dump, false,
>> "Print all allocations within [malloc_bisect_left, "
>> "malloc_bisect_right] range ")
>> +
>> +
>> +// Exit if we fail to enable the AArch64 kernel ABI relaxation which allows
>> +// tagged pointers in syscalls. This is the default, but being able to disable
>> +// that behaviour is useful for running the testsuite on more platforms (the
>> +// testsuite can run since we manually ensure any pointer arguments to syscalls
>> +// are untagged before the call.
>> +HWASAN_FLAG(bool, fail_without_syscall_abi, true,
>> + "Exit if fail to request relaxed syscall ABI.")
>> diff --git a/libsanitizer/hwasan/hwasan_interceptors.cpp b/libsanitizer/hwasan/hwasan_interceptors.cpp
>> index 44e569ee6d7..ad67e2787d3 100644
>> --- a/libsanitizer/hwasan/hwasan_interceptors.cpp
>> +++ b/libsanitizer/hwasan/hwasan_interceptors.cpp
>> @@ -221,8 +221,7 @@ INTERCEPTOR(int, pthread_create, void *th, void *attr, void *(*callback)(void*),
>> ThreadStartArg *A = reinterpret_cast<ThreadStartArg *> (MmapOrDie(
>> GetPageSizeCached(), "pthread_create"));
>> *A = {callback, param};
>> - int res = REAL(pthread_create)(UntagPtr(th), UntagPtr(attr),
>> - &HwasanThreadStartFunc, A);
>> + int res = REAL(pthread_create)(th, attr, &HwasanThreadStartFunc, A);
>> return res;
>> }
>>
>> diff --git a/libsanitizer/hwasan/hwasan_interceptors_vfork.S b/libsanitizer/hwasan/hwasan_interceptors_vfork.S
>> index 23d565936d8..fd20825e3da 100644
>> --- a/libsanitizer/hwasan/hwasan_interceptors_vfork.S
>> +++ b/libsanitizer/hwasan/hwasan_interceptors_vfork.S
>> @@ -1,4 +1,5 @@
>> #include "sanitizer_common/sanitizer_asm.h"
>> +#include "builtins/assembly.h"
>>
>> #if defined(__linux__) && HWASAN_WITH_INTERCEPTORS
>> #define COMMON_INTERCEPTOR_SPILL_AREA __hwasan_extra_spill_area
>> @@ -9,3 +10,5 @@
>> #endif
>>
>> NO_EXEC_STACK_DIRECTIVE
>> +
>> +GNU_PROPERTY_BTI_PAC
>> diff --git a/libsanitizer/hwasan/hwasan_interface_internal.h b/libsanitizer/hwasan/hwasan_interface_internal.h
>> index aedda317497..25c0f94fe51 100644
>> --- a/libsanitizer/hwasan/hwasan_interface_internal.h
>> +++ b/libsanitizer/hwasan/hwasan_interface_internal.h
>> @@ -222,6 +222,9 @@ SANITIZER_INTERFACE_ATTRIBUTE
>> void *__hwasan_memset(void *s, int c, uptr n);
>> SANITIZER_INTERFACE_ATTRIBUTE
>> void *__hwasan_memmove(void *dest, const void *src, uptr n);
>> +
>> +SANITIZER_INTERFACE_ATTRIBUTE
>> +void __hwasan_set_error_report_callback(void (*callback)(const char *));
>> } // extern "C"
>>
>> #endif // HWASAN_INTERFACE_INTERNAL_H
>> diff --git a/libsanitizer/hwasan/hwasan_linux.cpp b/libsanitizer/hwasan/hwasan_linux.cpp
>> index e99926d355c..8ce0ff7da95 100644
>> --- a/libsanitizer/hwasan/hwasan_linux.cpp
>> +++ b/libsanitizer/hwasan/hwasan_linux.cpp
>> @@ -76,6 +76,8 @@ uptr kHighShadowEnd;
>> uptr kHighMemStart;
>> uptr kHighMemEnd;
>>
>> +uptr kAliasRegionStart; // Always 0 on non-x86.
>> +
>> static void PrintRange(uptr start, uptr end, const char *name) {
>> Printf("|| [%p, %p] || %.*s ||\n", (void *)start, (void *)end, 10, name);
>> }
>> @@ -119,9 +121,11 @@ void InitPrctl() {
>> #define PR_GET_TAGGED_ADDR_CTRL 56
>> #define PR_TAGGED_ADDR_ENABLE (1UL << 0)
>> // Check we're running on a kernel that can use the tagged address ABI.
>> - if (internal_prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0) == (uptr)-1 &&
>> - errno == EINVAL) {
>> -#if SANITIZER_ANDROID
>> + int local_errno = 0;
>> + if (internal_iserror(internal_prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0),
>> + &local_errno) &&
>> + local_errno == EINVAL) {
>> +#if SANITIZER_ANDROID || defined(__x86_64__)
>> // Some older Android kernels have the tagged pointer ABI on
>> // unconditionally, and hence don't have the tagged-addr prctl while still
>> // allow the ABI.
>> @@ -129,17 +133,20 @@ void InitPrctl() {
>> // case.
>> return;
>> #else
>> - Printf(
>> - "FATAL: "
>> - "HWAddressSanitizer requires a kernel with tagged address ABI.\n");
>> - Die();
>> + if (flags()->fail_without_syscall_abi) {
>> + Printf(
>> + "FATAL: "
>> + "HWAddressSanitizer requires a kernel with tagged address ABI.\n");
>> + Die();
>> + }
>> #endif
>> }
>>
>> // Turn on the tagged address ABI.
>> - if (internal_prctl(PR_SET_TAGGED_ADDR_CTRL, PR_TAGGED_ADDR_ENABLE, 0, 0, 0) ==
>> - (uptr)-1 ||
>> - !internal_prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0)) {
>> + if ((internal_iserror(internal_prctl(PR_SET_TAGGED_ADDR_CTRL,
>> + PR_TAGGED_ADDR_ENABLE, 0, 0, 0)) ||
>> + !internal_prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0)) &&
>> + flags()->fail_without_syscall_abi) {
>> Printf(
>> "FATAL: HWAddressSanitizer failed to enable tagged address syscall "
>> "ABI.\nSuggest check `sysctl abi.tagged_addr_disabled` "
>> @@ -174,6 +181,18 @@ bool InitShadow() {
>> // High memory starts where allocated shadow allows.
>> kHighMemStart = ShadowToMem(kHighShadowStart);
>>
>> +#if defined(__x86_64__)
>> + constexpr uptr kAliasRegionOffset = 1ULL << (kTaggableRegionCheckShift - 1);
>> + kAliasRegionStart =
>> + __hwasan_shadow_memory_dynamic_address + kAliasRegionOffset;
>> +
>> + CHECK_EQ(kAliasRegionStart >> kTaggableRegionCheckShift,
>> + __hwasan_shadow_memory_dynamic_address >> kTaggableRegionCheckShift);
>> + CHECK_EQ(
>> + (kAliasRegionStart + kAliasRegionOffset - 1) >> kTaggableRegionCheckShift,
>> + __hwasan_shadow_memory_dynamic_address >> kTaggableRegionCheckShift);
>> +#endif
>> +
>> // Check the sanity of the defined memory ranges (there might be gaps).
>> CHECK_EQ(kHighMemStart % GetMmapGranularity(), 0);
>> CHECK_GT(kHighMemStart, kHighShadowEnd);
>> @@ -217,7 +236,9 @@ void InitThreads() {
>> }
>>
>> bool MemIsApp(uptr p) {
>> +#if !defined(__x86_64__) // Memory outside the alias range has non-zero tags.
>> CHECK(GetTagFromPointer(p) == 0);
>> +#endif
>> return p >= kHighMemStart || (p >= kLowMemStart && p <= kLowMemEnd);
>> }
>>
>> diff --git a/libsanitizer/hwasan/hwasan_mapping.h b/libsanitizer/hwasan/hwasan_mapping.h
>> index c149687bdfa..8243d1ec7ed 100644
>> --- a/libsanitizer/hwasan/hwasan_mapping.h
>> +++ b/libsanitizer/hwasan/hwasan_mapping.h
>> @@ -48,6 +48,8 @@ extern uptr kHighShadowEnd;
>> extern uptr kHighMemStart;
>> extern uptr kHighMemEnd;
>>
>> +extern uptr kAliasRegionStart;
>> +
>> inline uptr MemToShadow(uptr untagged_addr) {
>> return (untagged_addr >> kShadowScale) +
>> __hwasan_shadow_memory_dynamic_address;
>> diff --git a/libsanitizer/hwasan/hwasan_memintrinsics.cpp b/libsanitizer/hwasan/hwasan_memintrinsics.cpp
>> index e82d77a1bc1..fab017aae60 100644
>> --- a/libsanitizer/hwasan/hwasan_memintrinsics.cpp
>> +++ b/libsanitizer/hwasan/hwasan_memintrinsics.cpp
>> @@ -24,7 +24,7 @@ using namespace __hwasan;
>> void *__hwasan_memset(void *block, int c, uptr size) {
>> CheckAddressSized<ErrorAction::Recover, AccessType::Store>(
>> reinterpret_cast<uptr>(block), size);
>> - return memset(UntagPtr(block), c, size);
>> + return memset(block, c, size);
>> }
>>
>> void *__hwasan_memcpy(void *to, const void *from, uptr size) {
>> @@ -32,7 +32,7 @@ void *__hwasan_memcpy(void *to, const void *from, uptr size) {
>> reinterpret_cast<uptr>(to), size);
>> CheckAddressSized<ErrorAction::Recover, AccessType::Load>(
>> reinterpret_cast<uptr>(from), size);
>> - return memcpy(UntagPtr(to), UntagPtr(from), size);
>> + return memcpy(to, from, size);
>> }
>>
>> void *__hwasan_memmove(void *to, const void *from, uptr size) {
>> diff --git a/libsanitizer/hwasan/hwasan_new_delete.cpp b/libsanitizer/hwasan/hwasan_new_delete.cpp
>> index 8d01d3944f2..69cddda736e 100644
>> --- a/libsanitizer/hwasan/hwasan_new_delete.cpp
>> +++ b/libsanitizer/hwasan/hwasan_new_delete.cpp
>> @@ -27,6 +27,12 @@
>> void *res = hwasan_malloc(size, &stack);\
>> if (!nothrow && UNLIKELY(!res)) ReportOutOfMemory(size, &stack);\
>> return res
>> +#define OPERATOR_NEW_ALIGN_BODY(nothrow) \
>> + GET_MALLOC_STACK_TRACE; \
>> + void *res = hwasan_aligned_alloc(static_cast<uptr>(align), size, &stack); \
>> + if (!nothrow && UNLIKELY(!res)) \
>> + ReportOutOfMemory(size, &stack); \
>> + return res
>>
>> #define OPERATOR_DELETE_BODY \
>> GET_MALLOC_STACK_TRACE; \
>> @@ -50,6 +56,7 @@ using namespace __hwasan;
>> // Fake std::nothrow_t to avoid including <new>.
>> namespace std {
>> struct nothrow_t {};
>> + enum class align_val_t : size_t {};
>> } // namespace std
>>
>>
>> @@ -66,6 +73,22 @@ INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
>> void *operator new[](size_t size, std::nothrow_t const&) {
>> OPERATOR_NEW_BODY(true /*nothrow*/);
>> }
>> +INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void *operator new(
>> + size_t size, std::align_val_t align) {
>> + OPERATOR_NEW_ALIGN_BODY(false /*nothrow*/);
>> +}
>> +INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void *operator new[](
>> + size_t size, std::align_val_t align) {
>> + OPERATOR_NEW_ALIGN_BODY(false /*nothrow*/);
>> +}
>> +INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void *operator new(
>> + size_t size, std::align_val_t align, std::nothrow_t const &) {
>> + OPERATOR_NEW_ALIGN_BODY(true /*nothrow*/);
>> +}
>> +INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void *operator new[](
>> + size_t size, std::align_val_t align, std::nothrow_t const &) {
>> + OPERATOR_NEW_ALIGN_BODY(true /*nothrow*/);
>> +}
>>
>> INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
>> void operator delete(void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY; }
>> @@ -77,5 +100,21 @@ INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
>> void operator delete[](void *ptr, std::nothrow_t const&) {
>> OPERATOR_DELETE_BODY;
>> }
>> +INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void operator delete(
>> + void *ptr, std::align_val_t align) NOEXCEPT {
>> + OPERATOR_DELETE_BODY;
>> +}
>> +INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void operator delete[](
>> + void *ptr, std::align_val_t) NOEXCEPT {
>> + OPERATOR_DELETE_BODY;
>> +}
>> +INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void operator delete(
>> + void *ptr, std::align_val_t, std::nothrow_t const &) NOEXCEPT {
>> + OPERATOR_DELETE_BODY;
>> +}
>> +INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void operator delete[](
>> + void *ptr, std::align_val_t, std::nothrow_t const &) NOEXCEPT {
>> + OPERATOR_DELETE_BODY;
>> +}
>>
>> #endif // OPERATOR_NEW_BODY
>> diff --git a/libsanitizer/hwasan/hwasan_report.cpp b/libsanitizer/hwasan/hwasan_report.cpp
>> index 894a149775f..c0217799391 100644
>> --- a/libsanitizer/hwasan/hwasan_report.cpp
>> +++ b/libsanitizer/hwasan/hwasan_report.cpp
>> @@ -43,12 +43,16 @@ class ScopedReport {
>> }
>>
>> ~ScopedReport() {
>> + void (*report_cb)(const char *);
>> {
>> BlockingMutexLock lock(&error_message_lock_);
>> - if (fatal)
>> - SetAbortMessage(error_message_.data());
>> + report_cb = error_report_callback_;
>> error_message_ptr_ = nullptr;
>> }
>> + if (report_cb)
>> + report_cb(error_message_.data());
>> + if (fatal)
>> + SetAbortMessage(error_message_.data());
>> if (common_flags()->print_module_map >= 2 ||
>> (fatal && common_flags()->print_module_map))
>> DumpProcessMap();
>> @@ -66,6 +70,12 @@ class ScopedReport {
>> // overwrite old trailing '\0', keep new trailing '\0' untouched.
>> internal_memcpy(&(*error_message_ptr_)[old_size - 1], msg, len);
>> }
>> +
>> + static void SetErrorReportCallback(void (*callback)(const char *)) {
>> + BlockingMutexLock lock(&error_message_lock_);
>> + error_report_callback_ = callback;
>> + }
>> +
>> private:
>> ScopedErrorReportLock error_report_lock_;
>> InternalMmapVector<char> error_message_;
>> @@ -73,10 +83,12 @@ class ScopedReport {
>>
>> static InternalMmapVector<char> *error_message_ptr_;
>> static BlockingMutex error_message_lock_;
>> + static void (*error_report_callback_)(const char *);
>> };
>>
>> InternalMmapVector<char> *ScopedReport::error_message_ptr_;
>> BlockingMutex ScopedReport::error_message_lock_;
>> +void (*ScopedReport::error_report_callback_)(const char *);
>>
>> // If there is an active ScopedReport, append to its error message.
>> void AppendToErrorMessageBuffer(const char *buffer) {
>> @@ -212,7 +224,7 @@ static void PrintStackAllocations(StackAllocationsRingBuffer *sa,
>>
>> // We didn't find any locals. Most likely we don't have symbols, so dump
>> // the information that we have for offline analysis.
>> - InternalScopedString frame_desc(GetPageSizeCached() * 2);
>> + InternalScopedString frame_desc;
>> Printf("Previously allocated frames:\n");
>> for (uptr i = 0; i < frames; i++) {
>> const uptr *record_addr = &(*sa)[i];
>> @@ -447,7 +459,7 @@ static void PrintTagInfoAroundAddr(tag_t *tag_ptr, uptr num_rows,
>> RoundDownTo(reinterpret_cast<uptr>(tag_ptr), row_len));
>> tag_t *beg_row = center_row_beg - row_len * (num_rows / 2);
>> tag_t *end_row = center_row_beg + row_len * ((num_rows + 1) / 2);
>> - InternalScopedString s(GetPageSizeCached() * 8);
>> + InternalScopedString s;
>> for (tag_t *row = beg_row; row < end_row; row += row_len) {
>> s.append("%s", row == center_row_beg ? "=>" : " ");
>> s.append("%p:", row);
>> @@ -535,7 +547,7 @@ void ReportTailOverwritten(StackTrace *stack, uptr tagged_addr, uptr orig_size,
>> GetStackTraceFromId(chunk.GetAllocStackId()).Print();
>> }
>>
>> - InternalScopedString s(GetPageSizeCached() * 8);
>> + InternalScopedString s;
>> CHECK_GT(tail_size, 0U);
>> CHECK_LT(tail_size, kShadowAlignment);
>> u8 *tail = reinterpret_cast<u8*>(untagged_addr + orig_size);
>> @@ -650,3 +662,7 @@ void ReportRegisters(uptr *frame, uptr pc) {
>> }
>>
>> } // namespace __hwasan
>> +
>> +void __hwasan_set_error_report_callback(void (*callback)(const char *)) {
>> + __hwasan::ScopedReport::SetErrorReportCallback(callback);
>> +}
>> diff --git a/libsanitizer/hwasan/hwasan_setjmp.S b/libsanitizer/hwasan/hwasan_setjmp.S
>> index 0c135433194..381af63363c 100644
>> --- a/libsanitizer/hwasan/hwasan_setjmp.S
>> +++ b/libsanitizer/hwasan/hwasan_setjmp.S
>> @@ -12,6 +12,7 @@
>> //===----------------------------------------------------------------------===//
>>
>> #include "sanitizer_common/sanitizer_asm.h"
>> +#include "builtins/assembly.h"
>>
>> #if HWASAN_WITH_INTERCEPTORS && defined(__aarch64__)
>> #include "sanitizer_common/sanitizer_platform.h"
>> @@ -34,6 +35,7 @@
>> ASM_TYPE_FUNCTION(__interceptor_setjmp)
>> __interceptor_setjmp:
>> CFI_STARTPROC
>> + BTI_C
>> mov x1, #0
>> b __interceptor_sigsetjmp
>> CFI_ENDPROC
>> @@ -46,6 +48,7 @@ ASM_SIZE(__interceptor_setjmp)
>> ASM_TYPE_FUNCTION(__interceptor_setjmp_bionic)
>> __interceptor_setjmp_bionic:
>> CFI_STARTPROC
>> + BTI_C
>> mov x1, #1
>> b __interceptor_sigsetjmp
>> CFI_ENDPROC
>> @@ -56,6 +59,7 @@ ASM_SIZE(__interceptor_setjmp_bionic)
>> ASM_TYPE_FUNCTION(__interceptor_sigsetjmp)
>> __interceptor_sigsetjmp:
>> CFI_STARTPROC
>> + BTI_C
>> stp x19, x20, [x0, #0<<3]
>> stp x21, x22, [x0, #2<<3]
>> stp x23, x24, [x0, #4<<3]
>> @@ -98,3 +102,5 @@ ALIAS __interceptor_setjmp, _setjmp
>>
>> // We do not need executable stack.
>> NO_EXEC_STACK_DIRECTIVE
>> +
>> +GNU_PROPERTY_BTI_PAC
>> diff --git a/libsanitizer/hwasan/hwasan_tag_mismatch_aarch64.S b/libsanitizer/hwasan/hwasan_tag_mismatch_aarch64.S
>> index 08df12736bb..bcb0df42019 100644
>> --- a/libsanitizer/hwasan/hwasan_tag_mismatch_aarch64.S
>> +++ b/libsanitizer/hwasan/hwasan_tag_mismatch_aarch64.S
>> @@ -1,4 +1,5 @@
>> #include "sanitizer_common/sanitizer_asm.h"
>> +#include "builtins/assembly.h"
>>
>> // The content of this file is AArch64-only:
>> #if defined(__aarch64__)
>> @@ -74,6 +75,8 @@
>> .global __hwasan_tag_mismatch
>> .type __hwasan_tag_mismatch, %function
>> __hwasan_tag_mismatch:
>> + BTI_J
>> +
>> // Compute the granule position one past the end of the access.
>> mov x16, #1
>> and x17, x1, #0xf
>> @@ -106,6 +109,7 @@ __hwasan_tag_mismatch:
>> .type __hwasan_tag_mismatch_v2, %function
>> __hwasan_tag_mismatch_v2:
>> CFI_STARTPROC
>> + BTI_J
>>
>> // Set the CFA to be the return address for caller of __hwasan_check_*. Note
>> // that we do not emit CFI predicates to describe the contents of this stack
>> @@ -150,3 +154,5 @@ __hwasan_tag_mismatch_v2:
>>
>> // We do not need executable stack.
>> NO_EXEC_STACK_DIRECTIVE
>> +
>> +GNU_PROPERTY_BTI_PAC
>> diff --git a/libsanitizer/hwasan/hwasan_thread.cpp b/libsanitizer/hwasan/hwasan_thread.cpp
>> index b81a6350c05..bb4d56abed0 100644
>> --- a/libsanitizer/hwasan/hwasan_thread.cpp
>> +++ b/libsanitizer/hwasan/hwasan_thread.cpp
>> @@ -35,6 +35,10 @@ void Thread::InitRandomState() {
>> }
>>
>> void Thread::Init(uptr stack_buffer_start, uptr stack_buffer_size) {
>> + CHECK_EQ(0, unique_id_); // try to catch bad stack reuse
>> + CHECK_EQ(0, stack_top_);
>> + CHECK_EQ(0, stack_bottom_);
>> +
>> static u64 unique_id;
>> unique_id_ = unique_id++;
>> if (auto sz = flags()->heap_history_size)
>> @@ -113,18 +117,21 @@ static u32 xorshift(u32 state) {
>> }
>>
>> // Generate a (pseudo-)random non-zero tag.
>> -tag_t Thread::GenerateRandomTag() {
>> +tag_t Thread::GenerateRandomTag(uptr num_bits) {
>> + DCHECK_GT(num_bits, 0);
>> if (tagging_disabled_) return 0;
>> tag_t tag;
>> + const uptr tag_mask = (1ULL << num_bits) - 1;
>> do {
>> if (flags()->random_tags) {
>> if (!random_buffer_)
>> random_buffer_ = random_state_ = xorshift(random_state_);
>> CHECK(random_buffer_);
>> - tag = random_buffer_ & 0xFF;
>> - random_buffer_ >>= 8;
>> + tag = random_buffer_ & tag_mask;
>> + random_buffer_ >>= num_bits;
>> } else {
>> - tag = random_state_ = (random_state_ + 1) & 0xFF;
>> + random_state_ += 1;
>> + tag = random_state_ & tag_mask;
>> }
>> } while (!tag);
>> return tag;
>> diff --git a/libsanitizer/hwasan/hwasan_thread.h b/libsanitizer/hwasan/hwasan_thread.h
>> index ebcdb791fb3..1c71cab41c4 100644
>> --- a/libsanitizer/hwasan/hwasan_thread.h
>> +++ b/libsanitizer/hwasan/hwasan_thread.h
>> @@ -42,7 +42,7 @@ class Thread {
>> HeapAllocationsRingBuffer *heap_allocations() { return heap_allocations_; }
>> StackAllocationsRingBuffer *stack_allocations() { return stack_allocations_; }
>>
>> - tag_t GenerateRandomTag();
>> + tag_t GenerateRandomTag(uptr num_bits = kTagBits);
>>
>> void DisableTagging() { tagging_disabled_++; }
>> void EnableTagging() { tagging_disabled_--; }
>> @@ -74,8 +74,6 @@ class Thread {
>> HeapAllocationsRingBuffer *heap_allocations_;
>> StackAllocationsRingBuffer *stack_allocations_;
>>
>> - Thread *next_; // All live threads form a linked list.
>> -
>> u64 unique_id_; // counting from zero.
>>
>> u32 tagging_disabled_; // if non-zero, malloc uses zero tag in this thread.
>> diff --git a/libsanitizer/hwasan/hwasan_thread_list.h b/libsanitizer/hwasan/hwasan_thread_list.h
>> index 914b632d977..11c586314ce 100644
>> --- a/libsanitizer/hwasan/hwasan_thread_list.h
>> +++ b/libsanitizer/hwasan/hwasan_thread_list.h
>> @@ -66,40 +66,6 @@ static uptr RingBufferSize() {
>> return 0;
>> }
>>
>> -struct ThreadListHead {
>> - Thread *list_;
>> -
>> - ThreadListHead() : list_(nullptr) {}
>> -
>> - void Push(Thread *t) {
>> - t->next_ = list_;
>> - list_ = t;
>> - }
>> -
>> - Thread *Pop() {
>> - Thread *t = list_;
>> - if (t)
>> - list_ = t->next_;
>> - return t;
>> - }
>> -
>> - void Remove(Thread *t) {
>> - Thread **cur = &list_;
>> - while (*cur != t) cur = &(*cur)->next_;
>> - CHECK(*cur && "thread not found");
>> - *cur = (*cur)->next_;
>> - }
>> -
>> - template <class CB>
>> - void ForEach(CB cb) {
>> - Thread *t = list_;
>> - while (t) {
>> - cb(t);
>> - t = t->next_;
>> - }
>> - }
>> -};
>> -
>> struct ThreadStats {
>> uptr n_live_threads;
>> uptr total_stack_size;
>> @@ -120,17 +86,23 @@ class HwasanThreadList {
>> }
>>
>> Thread *CreateCurrentThread() {
>> - Thread *t;
>> + Thread *t = nullptr;
>> {
>> - SpinMutexLock l(&list_mutex_);
>> - t = free_list_.Pop();
>> - if (t) {
>> - uptr start = (uptr)t - ring_buffer_size_;
>> - internal_memset((void *)start, 0, ring_buffer_size_ + sizeof(Thread));
>> - } else {
>> - t = AllocThread();
>> + SpinMutexLock l(&free_list_mutex_);
>> + if (!free_list_.empty()) {
>> + t = free_list_.back();
>> + free_list_.pop_back();
>> }
>> - live_list_.Push(t);
>> + }
>> + if (t) {
>> + uptr start = (uptr)t - ring_buffer_size_;
>> + internal_memset((void *)start, 0, ring_buffer_size_ + sizeof(Thread));
>> + } else {
>> + t = AllocThread();
>> + }
>> + {
>> + SpinMutexLock l(&live_list_mutex_);
>> + live_list_.push_back(t);
>> }
>> t->Init((uptr)t - ring_buffer_size_, ring_buffer_size_);
>> AddThreadStats(t);
>> @@ -142,13 +114,26 @@ class HwasanThreadList {
>> ReleaseMemoryPagesToOS(start, start + thread_alloc_size_);
>> }
>>
>> + void RemoveThreadFromLiveList(Thread *t) {
>> + SpinMutexLock l(&live_list_mutex_);
>> + for (Thread *&t2 : live_list_)
>> + if (t2 == t) {
>> + // To remove t2, copy the last element of the list in t2's position, and
>> + // pop_back(). This works even if t2 is itself the last element.
>> + t2 = live_list_.back();
>> + live_list_.pop_back();
>> + return;
>> + }
>> + CHECK(0 && "thread not found in live list");
>> + }
>> +
>> void ReleaseThread(Thread *t) {
>> RemoveThreadStats(t);
>> t->Destroy();
>> - SpinMutexLock l(&list_mutex_);
>> - live_list_.Remove(t);
>> - free_list_.Push(t);
>> DontNeedThread(t);
>> + RemoveThreadFromLiveList(t);
>> + SpinMutexLock l(&free_list_mutex_);
>> + free_list_.push_back(t);
>> }
>>
>> Thread *GetThreadByBufferAddress(uptr p) {
>> @@ -165,8 +150,8 @@ class HwasanThreadList {
>>
>> template <class CB>
>> void VisitAllLiveThreads(CB cb) {
>> - SpinMutexLock l(&list_mutex_);
>> - live_list_.ForEach(cb);
>> + SpinMutexLock l(&live_list_mutex_);
>> + for (Thread *t : live_list_) cb(t);
>> }
>>
>> void AddThreadStats(Thread *t) {
>> @@ -188,6 +173,7 @@ class HwasanThreadList {
>>
>> private:
>> Thread *AllocThread() {
>> + SpinMutexLock l(&free_space_mutex_);
>> uptr align = ring_buffer_size_ * 2;
>> CHECK(IsAligned(free_space_, align));
>> Thread *t = (Thread *)(free_space_ + ring_buffer_size_);
>> @@ -196,14 +182,16 @@ class HwasanThreadList {
>> return t;
>> }
>>
>> + SpinMutex free_space_mutex_;
>> uptr free_space_;
>> uptr free_space_end_;
>> uptr ring_buffer_size_;
>> uptr thread_alloc_size_;
>>
>> - ThreadListHead free_list_;
>> - ThreadListHead live_list_;
>> - SpinMutex list_mutex_;
>> + SpinMutex free_list_mutex_;
>> + InternalMmapVector<Thread *> free_list_;
>> + SpinMutex live_list_mutex_;
>> + InternalMmapVector<Thread *> live_list_;
>>
>> ThreadStats stats_;
>> SpinMutex stats_mutex_;
>> diff --git a/libsanitizer/include/sanitizer/common_interface_defs.h b/libsanitizer/include/sanitizer/common_interface_defs.h
>> index b4f977bf557..cd69285b8d4 100644
>> --- a/libsanitizer/include/sanitizer/common_interface_defs.h
>> +++ b/libsanitizer/include/sanitizer/common_interface_defs.h
>> @@ -43,6 +43,9 @@ void __sanitizer_set_report_path(const char *path);
>> // Tell the tools to write their reports to the provided file descriptor
>> // (casted to void *).
>> void __sanitizer_set_report_fd(void *fd);
>> +// Get the current full report file path, if a path was specified by
>> +// an earlier call to __sanitizer_set_report_path. Returns null otherwise.
>> +const char *__sanitizer_get_report_path();
>>
>> // 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
>> diff --git a/libsanitizer/include/sanitizer/dfsan_interface.h b/libsanitizer/include/sanitizer/dfsan_interface.h
>> index 18b2c81a602..40f9379b557 100644
>> --- a/libsanitizer/include/sanitizer/dfsan_interface.h
>> +++ b/libsanitizer/include/sanitizer/dfsan_interface.h
>> @@ -22,6 +22,7 @@ extern "C" {
>> #endif
>>
>> typedef uint16_t dfsan_label;
>> +typedef uint32_t dfsan_origin;
>>
>> /// Stores information associated with a specific label identifier. A label
>> /// may be a base label created using dfsan_create_label, with associated
>> @@ -63,6 +64,12 @@ void dfsan_add_label(dfsan_label label, void *addr, size_t size);
>> /// value.
>> dfsan_label dfsan_get_label(long data);
>>
>> +/// Retrieves the immediate origin associated with the given data. The returned
>> +/// origin may point to another origin.
>> +///
>> +/// The type of 'data' is arbitrary.
>> +dfsan_origin dfsan_get_origin(long data);
>> +
>> /// Retrieves the label associated with the data at the given address.
>> dfsan_label dfsan_read_label(const void *addr, size_t size);
>>
>> @@ -110,6 +117,15 @@ void dfsan_weak_hook_memcmp(void *caller_pc, const void *s1, const void *s2,
>> void dfsan_weak_hook_strncmp(void *caller_pc, const char *s1, const char *s2,
>> size_t n, dfsan_label s1_label,
>> dfsan_label s2_label, dfsan_label n_label);
>> +
>> +/// Prints the origin trace of the label at the address addr to stderr. It also
>> +/// prints description at the beginning of the trace. If origin tracking is not
>> +/// on, or the address is not labeled, it prints nothing.
>> +void dfsan_print_origin_trace(const void *addr, const char *description);
>> +
>> +/// Retrieves the very first origin associated with the data at the given
>> +/// address.
>> +dfsan_origin dfsan_get_init_origin(const void *addr);
>> #ifdef __cplusplus
>> } // extern "C"
>>
>> diff --git a/libsanitizer/include/sanitizer/hwasan_interface.h b/libsanitizer/include/sanitizer/hwasan_interface.h
>> index 4c9ad13aa0c..14035c05c63 100644
>> --- a/libsanitizer/include/sanitizer/hwasan_interface.h
>> +++ b/libsanitizer/include/sanitizer/hwasan_interface.h
>> @@ -73,6 +73,9 @@ extern "C" {
>> * accessed through the pointer in x, or -1 if the whole range is good. */
>> intptr_t __hwasan_test_shadow(const volatile void *x, size_t size);
>>
>> + /* Sets the callback function to be called during HWASan error reporting. */
>> + void __hwasan_set_error_report_callback(void (*callback)(const char *));
>> +
>> int __sanitizer_posix_memalign(void **memptr, size_t alignment, size_t size);
>> void * __sanitizer_memalign(size_t alignment, size_t size);
>> void * __sanitizer_aligned_alloc(size_t alignment, size_t size);
>> diff --git a/libsanitizer/include/sanitizer/memprof_interface.h b/libsanitizer/include/sanitizer/memprof_interface.h
>> index a7212605100..76031de4014 100644
>> --- a/libsanitizer/include/sanitizer/memprof_interface.h
>> +++ b/libsanitizer/include/sanitizer/memprof_interface.h
>> @@ -53,6 +53,11 @@ void __memprof_print_accumulated_stats(void);
>> /// \returns Default options string.
>> const char *__memprof_default_options(void);
>>
>> +/// Prints the memory profile to the current profile file.
>> +///
>> +/// \returns 0 on success.
>> +int __memprof_profile_dump(void);
>> +
>> #ifdef __cplusplus
>> } // extern "C"
>> #endif
>> diff --git a/libsanitizer/include/sanitizer/tsan_interface.h b/libsanitizer/include/sanitizer/tsan_interface.h
>> index 96b8ad58541..565aa391a9f 100644
>> --- a/libsanitizer/include/sanitizer/tsan_interface.h
>> +++ b/libsanitizer/include/sanitizer/tsan_interface.h
>> @@ -67,6 +67,12 @@ static const unsigned __tsan_mutex_recursive_lock = 1 << 6;
>> // the corresponding __tsan_mutex_post_lock annotation.
>> static const unsigned __tsan_mutex_recursive_unlock = 1 << 7;
>>
>> +// Convenient composed constants.
>> +static const unsigned __tsan_mutex_try_read_lock =
>> + __tsan_mutex_read_lock | __tsan_mutex_try_lock;
>> +static const unsigned __tsan_mutex_try_read_lock_failed =
>> + __tsan_mutex_try_read_lock | __tsan_mutex_try_lock_failed;
>> +
>> // Annotate creation of a mutex.
>> // Supported flags: mutex creation flags.
>> void __tsan_mutex_create(void *addr, unsigned flags);
>> @@ -141,7 +147,7 @@ void __tsan_external_write(void *addr, void *caller_pc, void *tag);
>> // and freed by __tsan_destroy_fiber.
>> // - TSAN context of current fiber or thread can be obtained
>> // by calling __tsan_get_current_fiber.
>> -// - __tsan_switch_to_fiber should be called immediatly before switch
>> +// - __tsan_switch_to_fiber should be called immediately before switch
>> // to fiber, such as call of swapcontext.
>> // - Fiber name can be set by __tsan_set_fiber_name.
>> void *__tsan_get_current_fiber(void);
>> @@ -154,6 +160,15 @@ void __tsan_set_fiber_name(void *fiber, const char *name);
>> // Do not establish a happens-before relation between fibers
>> static const unsigned __tsan_switch_to_fiber_no_sync = 1 << 0;
>>
>> +// User-provided callback invoked on TSan initialization.
>> +void __tsan_on_initialize();
>> +
>> +// User-provided callback invoked on TSan shutdown.
>> +// `failed` - Nonzero if TSan did detect issues, zero otherwise.
>> +// Return `0` if TSan should exit as if no issues were detected. Return nonzero
>> +// if TSan should exit as if issues were detected.
>> +int __tsan_on_finalize(int failed);
>> +
>> #ifdef __cplusplus
>> } // extern "C"
>> #endif
>> diff --git a/libsanitizer/include/sanitizer/tsan_interface_atomic.h b/libsanitizer/include/sanitizer/tsan_interface_atomic.h
>> index 8052bc1d56b..5e41e2256c3 100644
>> --- a/libsanitizer/include/sanitizer/tsan_interface_atomic.h
>> +++ b/libsanitizer/include/sanitizer/tsan_interface_atomic.h
>> @@ -30,7 +30,7 @@ __extension__ typedef __int128 __tsan_atomic128;
>> #endif
>>
>> // Part of ABI, do not change.
>> -// https://github.com/llvm/llvm-project/blob/master/libcxx/include/atomic
>> +// https://github.com/llvm/llvm-project/blob/main/libcxx/include/atomic
>> typedef enum {
>> __tsan_memory_order_relaxed,
>> __tsan_memory_order_consume,
>> diff --git a/libsanitizer/interception/interception_linux.cpp b/libsanitizer/interception/interception_linux.cpp
>> index 6883608d44f..5111a87f0a6 100644
>> --- a/libsanitizer/interception/interception_linux.cpp
>> +++ b/libsanitizer/interception/interception_linux.cpp
>> @@ -63,8 +63,8 @@ bool InterceptFunction(const char *name, uptr *ptr_to_real, uptr func,
>> return addr && (func == wrapper);
>> }
>>
>> -// Android and Solaris do not have dlvsym
>> -#if !SANITIZER_ANDROID && !SANITIZER_SOLARIS
>> +// dlvsym is a GNU extension supported by some other platforms.
>> +#if SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD
>> static void *GetFuncAddr(const char *name, const char *ver) {
>> return dlvsym(RTLD_NEXT, name, ver);
>> }
>> @@ -75,7 +75,7 @@ bool InterceptFunction(const char *name, const char *ver, uptr *ptr_to_real,
>> *ptr_to_real = (uptr)addr;
>> return addr && (func == wrapper);
>> }
>> -#endif // !SANITIZER_ANDROID
>> +#endif // SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD
>>
>> } // namespace __interception
>>
>> diff --git a/libsanitizer/interception/interception_linux.h b/libsanitizer/interception/interception_linux.h
>> index 097375fd1c1..a08f8cb98c4 100644
>> --- a/libsanitizer/interception/interception_linux.h
>> +++ b/libsanitizer/interception/interception_linux.h
>> @@ -35,8 +35,8 @@ bool InterceptFunction(const char *name, const char *ver, uptr *ptr_to_real,
>> (::__interception::uptr) & (func), \
>> (::__interception::uptr) & WRAP(func))
>>
>> -// Android and Solaris do not have dlvsym
>> -#if !SANITIZER_ANDROID && !SANITIZER_SOLARIS
>> +// dlvsym is a GNU extension supported by some other platforms.
>> +#if SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD
>> #define INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver) \
>> ::__interception::InterceptFunction( \
>> #func, symver, \
>> @@ -46,7 +46,7 @@ bool InterceptFunction(const char *name, const char *ver, uptr *ptr_to_real,
>> #else
>> #define INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver) \
>> INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func)
>> -#endif // !SANITIZER_ANDROID && !SANITIZER_SOLARIS
>> +#endif // SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD
>>
>> #endif // INTERCEPTION_LINUX_H
>> #endif // SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD ||
>> diff --git a/libsanitizer/interception/interception_win.cpp b/libsanitizer/interception/interception_win.cpp
>> index 1a1c327e612..98bc756ae53 100644
>> --- a/libsanitizer/interception/interception_win.cpp
>> +++ b/libsanitizer/interception/interception_win.cpp
>> @@ -136,7 +136,7 @@ namespace __interception {
>> static const int kAddressLength = FIRST_32_SECOND_64(4, 8);
>> static const int kJumpInstructionLength = 5;
>> static const int kShortJumpInstructionLength = 2;
>> -static const int kIndirectJumpInstructionLength = 6;
>> +UNUSED static const int kIndirectJumpInstructionLength = 6;
>> static const int kBranchLength =
>> FIRST_32_SECOND_64(kJumpInstructionLength, kIndirectJumpInstructionLength);
>> static const int kDirectBranchLength = kBranchLength + kAddressLength;
>> @@ -165,7 +165,7 @@ static uptr GetMmapGranularity() {
>> return si.dwAllocationGranularity;
>> }
>>
>> -static uptr RoundUpTo(uptr size, uptr boundary) {
>> +UNUSED static uptr RoundUpTo(uptr size, uptr boundary) {
>> return (size + boundary - 1) & ~(boundary - 1);
>> }
>>
>> @@ -309,7 +309,7 @@ struct TrampolineMemoryRegion {
>> uptr max_size;
>> };
>>
>> -static const uptr kTrampolineScanLimitRange = 1 << 31; // 2 gig
>> +UNUSED static const uptr kTrampolineScanLimitRange = 1 << 31; // 2 gig
>> static const int kMaxTrampolineRegion = 1024;
>> static TrampolineMemoryRegion TrampolineRegions[kMaxTrampolineRegion];
>>
>> diff --git a/libsanitizer/lsan/lsan_allocator.cpp b/libsanitizer/lsan/lsan_allocator.cpp
>> index d86c3921395..91e34ebb321 100644
>> --- a/libsanitizer/lsan/lsan_allocator.cpp
>> +++ b/libsanitizer/lsan/lsan_allocator.cpp
>> @@ -123,14 +123,18 @@ void Deallocate(void *p) {
>>
>> void *Reallocate(const StackTrace &stack, void *p, uptr new_size,
>> uptr alignment) {
>> - RegisterDeallocation(p);
>> if (new_size > max_malloc_size) {
>> - allocator.Deallocate(GetAllocatorCache(), p);
>> - return ReportAllocationSizeTooBig(new_size, stack);
>> + ReportAllocationSizeTooBig(new_size, stack);
>> + return nullptr;
>> }
>> - p = allocator.Reallocate(GetAllocatorCache(), p, new_size, alignment);
>> - RegisterAllocation(stack, p, new_size);
>> - return p;
>> + RegisterDeallocation(p);
>> + void *new_p =
>> + allocator.Reallocate(GetAllocatorCache(), p, new_size, alignment);
>> + if (new_p)
>> + RegisterAllocation(stack, new_p, new_size);
>> + else if (new_size != 0)
>> + RegisterAllocation(stack, p, new_size);
>> + return new_p;
>> }
>>
>> void GetAllocatorCacheRange(uptr *begin, uptr *end) {
>> @@ -309,6 +313,16 @@ IgnoreObjectResult IgnoreObjectLocked(const void *p) {
>> return kIgnoreObjectInvalid;
>> }
>> }
>> +
>> +void GetAdditionalThreadContextPtrs(ThreadContextBase *tctx, void *ptrs) {
>> + // This function can be used to treat memory reachable from `tctx` as live.
>> + // This is useful for threads that have been created but not yet started.
>> +
>> + // This is currently a no-op because the LSan `pthread_create()` interceptor
>> + // blocks until the child thread starts which keeps the thread's `arg` pointer
>> + // live.
>> +}
>> +
>> } // namespace __lsan
>>
>> using namespace __lsan;
>> diff --git a/libsanitizer/lsan/lsan_allocator.h b/libsanitizer/lsan/lsan_allocator.h
>> index 17e13cd014b..9d763789154 100644
>> --- a/libsanitizer/lsan/lsan_allocator.h
>> +++ b/libsanitizer/lsan/lsan_allocator.h
>> @@ -50,7 +50,7 @@ struct ChunkMetadata {
>> };
>>
>> #if defined(__mips64) || defined(__aarch64__) || defined(__i386__) || \
>> - defined(__arm__)
>> + defined(__arm__) || SANITIZER_RISCV64
>> template <typename AddressSpaceViewTy>
>> struct AP32 {
>> static const uptr kSpaceBeg = 0;
>> diff --git a/libsanitizer/lsan/lsan_common.cpp b/libsanitizer/lsan/lsan_common.cpp
>> index 9e23aa9997a..74400d2e842 100644
>> --- a/libsanitizer/lsan/lsan_common.cpp
>> +++ b/libsanitizer/lsan/lsan_common.cpp
>> @@ -65,8 +65,34 @@ void RegisterLsanFlags(FlagParser *parser, Flags *f) {
>> if (flags()->log_threads) Report(__VA_ARGS__); \
>> } while (0)
>>
>> -ALIGNED(64) static char suppression_placeholder[sizeof(SuppressionContext)];
>> -static SuppressionContext *suppression_ctx = nullptr;
>> +class LeakSuppressionContext {
>> + bool parsed = false;
>> + SuppressionContext context;
>> + bool suppressed_stacks_sorted = true;
>> + InternalMmapVector<u32> suppressed_stacks;
>> +
>> + Suppression *GetSuppressionForAddr(uptr addr);
>> + void LazyInit();
>> +
>> + public:
>> + LeakSuppressionContext(const char *supprression_types[],
>> + int suppression_types_num)
>> + : context(supprression_types, suppression_types_num) {}
>> +
>> + Suppression *GetSuppressionForStack(u32 stack_trace_id);
>> +
>> + const InternalMmapVector<u32> &GetSortedSuppressedStacks() {
>> + if (!suppressed_stacks_sorted) {
>> + suppressed_stacks_sorted = true;
>> + SortAndDedup(suppressed_stacks);
>> + }
>> + return suppressed_stacks;
>> + }
>> + void PrintMatchedSuppressions();
>> +};
>> +
>> +ALIGNED(64) static char suppression_placeholder[sizeof(LeakSuppressionContext)];
>> +static LeakSuppressionContext *suppression_ctx = nullptr;
>> static const char kSuppressionLeak[] = "leak";
>> static const char *kSuppressionTypes[] = { kSuppressionLeak };
>> static const char kStdSuppressions[] =
>> @@ -86,14 +112,20 @@ static const char kStdSuppressions[] =
>> void InitializeSuppressions() {
>> CHECK_EQ(nullptr, suppression_ctx);
>> suppression_ctx = new (suppression_placeholder)
>> - SuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes));
>> - suppression_ctx->ParseFromFile(flags()->suppressions);
>> - if (&__lsan_default_suppressions)
>> - suppression_ctx->Parse(__lsan_default_suppressions());
>> - suppression_ctx->Parse(kStdSuppressions);
>> + LeakSuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes));
>> +}
>> +
>> +void LeakSuppressionContext::LazyInit() {
>> + if (!parsed) {
>> + parsed = true;
>> + context.ParseFromFile(flags()->suppressions);
>> + if (&__lsan_default_suppressions)
>> + context.Parse(__lsan_default_suppressions());
>> + context.Parse(kStdSuppressions);
>> + }
>> }
>>
>> -static SuppressionContext *GetSuppressionContext() {
>> +static LeakSuppressionContext *GetSuppressionContext() {
>> CHECK(suppression_ctx);
>> return suppression_ctx;
>> }
>> @@ -221,6 +253,27 @@ extern "C" SANITIZER_WEAK_ATTRIBUTE void __libc_iterate_dynamic_tls(
>> pid_t, void (*cb)(void *, void *, uptr, void *), void *);
>> #endif
>>
>> +static void ProcessThreadRegistry(Frontier *frontier) {
>> + InternalMmapVector<uptr> ptrs;
>> + GetThreadRegistryLocked()->RunCallbackForEachThreadLocked(
>> + GetAdditionalThreadContextPtrs, &ptrs);
>> +
>> + for (uptr i = 0; i < ptrs.size(); ++i) {
>> + void *ptr = reinterpret_cast<void *>(ptrs[i]);
>> + uptr chunk = PointsIntoChunk(ptr);
>> + if (!chunk)
>> + continue;
>> + LsanMetadata m(chunk);
>> + if (!m.allocated())
>> + continue;
>> +
>> + // Mark as reachable and add to frontier.
>> + LOG_POINTERS("Treating pointer %p from ThreadContext as reachable\n", ptr);
>> + m.set_tag(kReachable);
>> + frontier->push_back(chunk);
>> + }
>> +}
>> +
>> // Scans thread data (stacks and TLS) for heap pointers.
>> static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
>> Frontier *frontier) {
>> @@ -315,15 +368,15 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
>> __libc_iterate_dynamic_tls(os_id, cb, frontier);
>> #else
>> if (dtls && !DTLSInDestruction(dtls)) {
>> - for (uptr j = 0; j < dtls->dtv_size; ++j) {
>> - uptr dtls_beg = dtls->dtv[j].beg;
>> - uptr dtls_end = dtls_beg + dtls->dtv[j].size;
>> + ForEachDVT(dtls, [&](const DTLS::DTV &dtv, int id) {
>> + uptr dtls_beg = dtv.beg;
>> + uptr dtls_end = dtls_beg + dtv.size;
>> if (dtls_beg < dtls_end) {
>> - LOG_THREADS("DTLS %zu at %p-%p.\n", j, dtls_beg, dtls_end);
>> + LOG_THREADS("DTLS %zu at %p-%p.\n", id, dtls_beg, dtls_end);
>> ScanRangeForPointers(dtls_beg, dtls_end, frontier, "DTLS",
>> kReachable);
>> }
>> - }
>> + });
>> } else {
>> // We are handling a thread with DTLS under destruction. Log about
>> // this and continue.
>> @@ -332,6 +385,9 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
>> #endif
>> }
>> }
>> +
>> + // Add pointers reachable from ThreadContexts
>> + ProcessThreadRegistry(frontier);
>> }
>>
>> #endif // SANITIZER_FUCHSIA
>> @@ -390,6 +446,24 @@ static void MarkIndirectlyLeakedCb(uptr chunk, void *arg) {
>> }
>> }
>>
>> +static void IgnoredSuppressedCb(uptr chunk, void *arg) {
>> + CHECK(arg);
>> + chunk = GetUserBegin(chunk);
>> + LsanMetadata m(chunk);
>> + if (!m.allocated() || m.tag() == kIgnored)
>> + return;
>> +
>> + const InternalMmapVector<u32> &suppressed =
>> + *static_cast<const InternalMmapVector<u32> *>(arg);
>> + uptr idx = InternalLowerBound(suppressed, m.stack_trace_id());
>> + if (idx >= suppressed.size() || m.stack_trace_id() != suppressed[idx])
>> + return;
>> +
>> + LOG_POINTERS("Suppressed: chunk %p-%p of size %zu.\n", chunk,
>> + chunk + m.requested_size(), m.requested_size());
>> + m.set_tag(kIgnored);
>> +}
>> +
>> // ForEachChunk callback. If chunk is marked as ignored, adds its address to
>> // frontier.
>> static void CollectIgnoredCb(uptr chunk, void *arg) {
>> @@ -473,6 +547,12 @@ void ProcessPC(Frontier *frontier) {
>> // Sets the appropriate tag on each chunk.
>> static void ClassifyAllChunks(SuspendedThreadsList const &suspended_threads,
>> Frontier *frontier) {
>> + const InternalMmapVector<u32> &suppressed_stacks =
>> + GetSuppressionContext()->GetSortedSuppressedStacks();
>> + if (!suppressed_stacks.empty()) {
>> + ForEachChunk(IgnoredSuppressedCb,
>> + const_cast<InternalMmapVector<u32> *>(&suppressed_stacks));
>> + }
>> ForEachChunk(CollectIgnoredCb, frontier);
>> ProcessGlobalRegions(frontier);
>> ProcessThreads(suspended_threads, frontier);
>> @@ -532,18 +612,20 @@ static void CollectLeaksCb(uptr chunk, void *arg) {
>> }
>> }
>>
>> -static void PrintMatchedSuppressions() {
>> +void LeakSuppressionContext::PrintMatchedSuppressions() {
>> InternalMmapVector<Suppression *> matched;
>> - GetSuppressionContext()->GetMatched(&matched);
>> + context.GetMatched(&matched);
>> if (!matched.size())
>> return;
>> const char *line = "-----------------------------------------------------";
>> Printf("%s\n", line);
>> Printf("Suppressions used:\n");
>> Printf(" count bytes template\n");
>> - for (uptr i = 0; i < matched.size(); i++)
>> - Printf("%7zu %10zu %s\n", static_cast<uptr>(atomic_load_relaxed(
>> - &matched[i]->hit_count)), matched[i]->weight, matched[i]->templ);
>> + for (uptr i = 0; i < matched.size(); i++) {
>> + Printf("%7zu %10zu %s\n",
>> + static_cast<uptr>(atomic_load_relaxed(&matched[i]->hit_count)),
>> + matched[i]->weight, matched[i]->templ);
>> + }
>> Printf("%s\n\n", line);
>> }
>>
>> @@ -551,8 +633,7 @@ static void ReportIfNotSuspended(ThreadContextBase *tctx, void *arg) {
>> const InternalMmapVector<tid_t> &suspended_threads =
>> *(const InternalMmapVector<tid_t> *)arg;
>> if (tctx->status == ThreadStatusRunning) {
>> - uptr i = InternalLowerBound(suspended_threads, 0, suspended_threads.size(),
>> - tctx->os_id, CompareLess<int>());
>> + uptr i = InternalLowerBound(suspended_threads, tctx->os_id);
>> if (i >= suspended_threads.size() || suspended_threads[i] != tctx->os_id)
>> Report("Running thread %d was not suspended. False leaks are possible.\n",
>> tctx->os_id);
>> @@ -595,43 +676,68 @@ static void CheckForLeaksCallback(const SuspendedThreadsList &suspended_threads,
>> param->success = true;
>> }
>>
>> -static bool CheckForLeaks() {
>> - if (&__lsan_is_turned_off && __lsan_is_turned_off())
>> - return false;
>> - EnsureMainThreadIDIsCorrect();
>> - CheckForLeaksParam param;
>> - LockStuffAndStopTheWorld(CheckForLeaksCallback, ¶m);
>> -
>> - if (!param.success) {
>> - Report("LeakSanitizer has encountered a fatal error.\n");
>> - Report(
>> - "HINT: For debugging, try setting environment variable "
>> - "LSAN_OPTIONS=verbosity=1:log_threads=1\n");
>> - Report(
>> - "HINT: LeakSanitizer does not work under ptrace (strace, gdb, etc)\n");
>> - Die();
>> - }
>> - param.leak_report.ApplySuppressions();
>> - uptr unsuppressed_count = param.leak_report.UnsuppressedLeakCount();
>> - if (unsuppressed_count > 0) {
>> +static bool PrintResults(LeakReport &report) {
>> + uptr unsuppressed_count = report.UnsuppressedLeakCount();
>> + if (unsuppressed_count) {
>> Decorator d;
>> - Printf("\n"
>> - "================================================================="
>> - "\n");
>> + Printf(
>> + "\n"
>> + "================================================================="
>> + "\n");
>> Printf("%s", d.Error());
>> Report("ERROR: LeakSanitizer: detected memory leaks\n");
>> Printf("%s", d.Default());
>> - param.leak_report.ReportTopLeaks(flags()->max_leaks);
>> + report.ReportTopLeaks(flags()->max_leaks);
>> }
>> if (common_flags()->print_suppressions)
>> - PrintMatchedSuppressions();
>> + GetSuppressionContext()->PrintMatchedSuppressions();
>> if (unsuppressed_count > 0) {
>> - param.leak_report.PrintSummary();
>> + report.PrintSummary();
>> return true;
>> }
>> return false;
>> }
>>
>> +static bool CheckForLeaks() {
>> + if (&__lsan_is_turned_off && __lsan_is_turned_off())
>> + return false;
>> + // Inside LockStuffAndStopTheWorld we can't run symbolizer, so we can't match
>> + // suppressions. However if a stack id was previously suppressed, it should be
>> + // suppressed in future checks as well.
>> + for (int i = 0;; ++i) {
>> + EnsureMainThreadIDIsCorrect();
>> + CheckForLeaksParam param;
>> + LockStuffAndStopTheWorld(CheckForLeaksCallback, ¶m);
>> + if (!param.success) {
>> + Report("LeakSanitizer has encountered a fatal error.\n");
>> + Report(
>> + "HINT: For debugging, try setting environment variable "
>> + "LSAN_OPTIONS=verbosity=1:log_threads=1\n");
>> + Report(
>> + "HINT: LeakSanitizer does not work under ptrace (strace, gdb, "
>> + "etc)\n");
>> + Die();
>> + }
>> + // No new suppressions stacks, so rerun will not help and we can report.
>> + if (!param.leak_report.ApplySuppressions())
>> + return PrintResults(param.leak_report);
>> +
>> + // No indirect leaks to report, so we are done here.
>> + if (!param.leak_report.IndirectUnsuppressedLeakCount())
>> + return PrintResults(param.leak_report);
>> +
>> + if (i >= 8) {
>> + Report("WARNING: LeakSanitizer gave up on indirect leaks suppression.\n");
>> + return PrintResults(param.leak_report);
>> + }
>> +
>> + // We found a new previously unseen suppressed call stack. Rerun to make
>> + // sure it does not hold indirect leaks.
>> + VReport(1, "Rerun with %zu suppressed stacks.",
>> + GetSuppressionContext()->GetSortedSuppressedStacks().size());
>> + }
>> +}
>> +
>> static bool has_reported_leaks = false;
>> bool HasReportedLeaks() { return has_reported_leaks; }
>>
>> @@ -652,21 +758,20 @@ static int DoRecoverableLeakCheck() {
>>
>> void DoRecoverableLeakCheckVoid() { DoRecoverableLeakCheck(); }
>>
>> -static Suppression *GetSuppressionForAddr(uptr addr) {
>> +Suppression *LeakSuppressionContext::GetSuppressionForAddr(uptr addr) {
>> Suppression *s = nullptr;
>>
>> // Suppress by module name.
>> - SuppressionContext *suppressions = GetSuppressionContext();
>> if (const char *module_name =
>> Symbolizer::GetOrInit()->GetModuleNameForPc(addr))
>> - if (suppressions->Match(module_name, kSuppressionLeak, &s))
>> + if (context.Match(module_name, kSuppressionLeak, &s))
>> return s;
>>
>> // Suppress by file or function name.
>> SymbolizedStack *frames = Symbolizer::GetOrInit()->SymbolizePC(addr);
>> for (SymbolizedStack *cur = frames; cur; cur = cur->next) {
>> - if (suppressions->Match(cur->info.function, kSuppressionLeak, &s) ||
>> - suppressions->Match(cur->info.file, kSuppressionLeak, &s)) {
>> + if (context.Match(cur->info.function, kSuppressionLeak, &s) ||
>> + context.Match(cur->info.file, kSuppressionLeak, &s)) {
>> break;
>> }
>> }
>> @@ -674,12 +779,18 @@ static Suppression *GetSuppressionForAddr(uptr addr) {
>> return s;
>> }
>>
>> -static Suppression *GetSuppressionForStack(u32 stack_trace_id) {
>> +Suppression *LeakSuppressionContext::GetSuppressionForStack(
>> + u32 stack_trace_id) {
>> + LazyInit();
>> StackTrace stack = StackDepotGet(stack_trace_id);
>> for (uptr i = 0; i < stack.size; i++) {
>> Suppression *s = GetSuppressionForAddr(
>> StackTrace::GetPreviousInstructionPc(stack.trace[i]));
>> - if (s) return s;
>> + if (s) {
>> + suppressed_stacks_sorted = false;
>> + suppressed_stacks.push_back(stack_trace_id);
>> + return s;
>> + }
>> }
>> return nullptr;
>> }
>> @@ -784,22 +895,27 @@ void LeakReport::PrintSummary() {
>> bytes += leaks_[i].total_size;
>> allocations += leaks_[i].hit_count;
>> }
>> - InternalScopedString summary(kMaxSummaryLength);
>> + InternalScopedString summary;
>> summary.append("%zu byte(s) leaked in %zu allocation(s).", bytes,
>> allocations);
>> ReportErrorSummary(summary.data());
>> }
>>
>> -void LeakReport::ApplySuppressions() {
>> +uptr LeakReport::ApplySuppressions() {
>> + LeakSuppressionContext *suppressions = GetSuppressionContext();
>> + uptr new_suppressions = false;
>> for (uptr i = 0; i < leaks_.size(); i++) {
>> - Suppression *s = GetSuppressionForStack(leaks_[i].stack_trace_id);
>> + Suppression *s =
>> + suppressions->GetSuppressionForStack(leaks_[i].stack_trace_id);
>> if (s) {
>> s->weight += leaks_[i].total_size;
>> atomic_store_relaxed(&s->hit_count, atomic_load_relaxed(&s->hit_count) +
>> leaks_[i].hit_count);
>> leaks_[i].is_suppressed = true;
>> + ++new_suppressions;
>> }
>> }
>> + return new_suppressions;
>> }
>>
>> uptr LeakReport::UnsuppressedLeakCount() {
>> @@ -809,6 +925,14 @@ uptr LeakReport::UnsuppressedLeakCount() {
>> return result;
>> }
>>
>> +uptr LeakReport::IndirectUnsuppressedLeakCount() {
>> + uptr result = 0;
>> + for (uptr i = 0; i < leaks_.size(); i++)
>> + if (!leaks_[i].is_suppressed && !leaks_[i].is_directly_leaked)
>> + result++;
>> + return result;
>> +}
>> +
>> } // namespace __lsan
>> #else // CAN_SANITIZE_LEAKS
>> namespace __lsan {
>> diff --git a/libsanitizer/lsan/lsan_common.h b/libsanitizer/lsan/lsan_common.h
>> index 1fdce087b3a..fe855cf3754 100644
>> --- a/libsanitizer/lsan/lsan_common.h
>> +++ b/libsanitizer/lsan/lsan_common.h
>> @@ -41,6 +41,8 @@
>> #define CAN_SANITIZE_LEAKS 1
>> #elif defined(__arm__) && SANITIZER_LINUX
>> #define CAN_SANITIZE_LEAKS 1
>> +#elif SANITIZER_RISCV64 && SANITIZER_LINUX
>> +#define CAN_SANITIZE_LEAKS 1
>> #elif SANITIZER_NETBSD || SANITIZER_FUCHSIA
>> #define CAN_SANITIZE_LEAKS 1
>> #else
>> @@ -50,6 +52,7 @@
>> namespace __sanitizer {
>> class FlagParser;
>> class ThreadRegistry;
>> +class ThreadContextBase;
>> struct DTLS;
>> }
>>
>> @@ -63,8 +66,6 @@ enum ChunkTag {
>> kIgnored = 3
>> };
>>
>> -const u32 kInvalidTid = (u32) -1;
>> -
>> struct Flags {
>> #define LSAN_FLAG(Type, Name, DefaultValue, Description) Type Name;
>> #include "lsan_flags.inc"
>> @@ -103,8 +104,9 @@ class LeakReport {
>> ChunkTag tag);
>> void ReportTopLeaks(uptr max_leaks);
>> void PrintSummary();
>> - void ApplySuppressions();
>> + uptr ApplySuppressions();
>> uptr UnsuppressedLeakCount();
>> + uptr IndirectUnsuppressedLeakCount();
>>
>> private:
>> void PrintReportForLeak(uptr index);
>> @@ -141,6 +143,7 @@ InternalMmapVector<RootRegion> const *GetRootRegions();
>> void ScanRootRegion(Frontier *frontier, RootRegion const ®ion,
>> uptr region_begin, uptr region_end, bool is_readable);
>> void ForEachExtraStackRangeCb(uptr begin, uptr end, void* arg);
>> +void GetAdditionalThreadContextPtrs(ThreadContextBase *tctx, void *ptrs);
>> // Run stoptheworld while holding any platform-specific locks, as well as the
>> // allocator and thread registry locks.
>> void LockStuffAndStopTheWorld(StopTheWorldCallback callback,
>> diff --git a/libsanitizer/lsan/lsan_common_fuchsia.cpp b/libsanitizer/lsan/lsan_common_fuchsia.cpp
>> index 3c62c9433d3..2d35fa5b1cf 100644
>> --- a/libsanitizer/lsan/lsan_common_fuchsia.cpp
>> +++ b/libsanitizer/lsan/lsan_common_fuchsia.cpp
>> @@ -107,9 +107,7 @@ void LockStuffAndStopTheWorld(StopTheWorldCallback callback,
>> auto params = static_cast<const Params *>(data);
>> uptr begin = reinterpret_cast<uptr>(chunk);
>> uptr end = begin + size;
>> - auto i = __sanitizer::InternalLowerBound(params->allocator_caches, 0,
>> - params->allocator_caches.size(),
>> - begin, CompareLess<uptr>());
>> + auto i = __sanitizer::InternalLowerBound(params->allocator_caches, begin);
>> if (i < params->allocator_caches.size() &&
>> params->allocator_caches[i] >= begin &&
>> end - params->allocator_caches[i] <= sizeof(AllocatorCache)) {
>> diff --git a/libsanitizer/lsan/lsan_fuchsia.h b/libsanitizer/lsan/lsan_fuchsia.h
>> index 65d20ea2114..e730d8f25f2 100644
>> --- a/libsanitizer/lsan/lsan_fuchsia.h
>> +++ b/libsanitizer/lsan/lsan_fuchsia.h
>> @@ -23,7 +23,7 @@
>>
>> namespace __lsan {
>>
>> -class ThreadContext : public ThreadContextLsanBase {
>> +class ThreadContext final : public ThreadContextLsanBase {
>> public:
>> explicit ThreadContext(int tid);
>> void OnCreated(void *arg) override;
>> diff --git a/libsanitizer/lsan/lsan_interceptors.cpp b/libsanitizer/lsan/lsan_interceptors.cpp
>> index bf8d316770e..90a90a56c54 100644
>> --- a/libsanitizer/lsan/lsan_interceptors.cpp
>> +++ b/libsanitizer/lsan/lsan_interceptors.cpp
>> @@ -460,7 +460,7 @@ INTERCEPTOR(int, pthread_create, void *th, void *attr,
>> if (res == 0) {
>> int tid = ThreadCreate(GetCurrentThread(), *(uptr *)th,
>> IsStateDetached(detached));
>> - CHECK_NE(tid, 0);
>> + CHECK_NE(tid, kMainTid);
>> atomic_store(&p.tid, tid, memory_order_release);
>> while (atomic_load(&p.tid, memory_order_acquire) != 0)
>> internal_sched_yield();
>> diff --git a/libsanitizer/lsan/lsan_posix.cpp b/libsanitizer/lsan/lsan_posix.cpp
>> index 8e05915dd1b..5d1c3f6260d 100644
>> --- a/libsanitizer/lsan/lsan_posix.cpp
>> +++ b/libsanitizer/lsan/lsan_posix.cpp
>> @@ -48,7 +48,7 @@ void ThreadStart(u32 tid, tid_t os_id, ThreadType thread_type) {
>> OnStartedArgs args;
>> uptr stack_size = 0;
>> uptr tls_size = 0;
>> - GetThreadStackAndTls(tid == 0, &args.stack_begin, &stack_size,
>> + GetThreadStackAndTls(tid == kMainTid, &args.stack_begin, &stack_size,
>> &args.tls_begin, &tls_size);
>> args.stack_end = args.stack_begin + stack_size;
>> args.tls_end = args.tls_begin + tls_size;
>> @@ -75,8 +75,8 @@ bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end,
>> }
>>
>> void InitializeMainThread() {
>> - u32 tid = ThreadCreate(0, 0, true);
>> - CHECK_EQ(tid, 0);
>> + u32 tid = ThreadCreate(kMainTid, 0, true);
>> + CHECK_EQ(tid, kMainTid);
>> ThreadStart(tid, GetTid());
>> }
>>
>> diff --git a/libsanitizer/lsan/lsan_thread.cpp b/libsanitizer/lsan/lsan_thread.cpp
>> index 371a1f29dfe..8efb54a6fb7 100644
>> --- a/libsanitizer/lsan/lsan_thread.cpp
>> +++ b/libsanitizer/lsan/lsan_thread.cpp
>> @@ -94,7 +94,7 @@ void ThreadJoin(u32 tid) {
>> }
>>
>> void EnsureMainThreadIDIsCorrect() {
>> - if (GetCurrentThread() == 0)
>> + if (GetCurrentThread() == kMainTid)
>> CurrentThreadContext()->os_id = GetTid();
>> }
>>
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_combined.h b/libsanitizer/sanitizer_common/sanitizer_allocator_combined.h
>> index 33f89d6d499..eb836bc4787 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_allocator_combined.h
>> +++ b/libsanitizer/sanitizer_common/sanitizer_allocator_combined.h
>> @@ -35,9 +35,9 @@ class CombinedAllocator {
>> secondary_.InitLinkerInitialized();
>> }
>>
>> - void Init(s32 release_to_os_interval_ms) {
>> + void Init(s32 release_to_os_interval_ms, uptr heap_start = 0) {
>> stats_.Init();
>> - primary_.Init(release_to_os_interval_ms);
>> + primary_.Init(release_to_os_interval_ms, heap_start);
>> secondary_.Init();
>> }
>>
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_primary32.h b/libsanitizer/sanitizer_common/sanitizer_allocator_primary32.h
>> index b90dabbf776..fb5394cd39c 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_allocator_primary32.h
>> +++ b/libsanitizer/sanitizer_common/sanitizer_allocator_primary32.h
>> @@ -119,7 +119,8 @@ class SizeClassAllocator32 {
>> typedef SizeClassAllocator32<Params> ThisT;
>> typedef SizeClassAllocator32LocalCache<ThisT> AllocatorCache;
>>
>> - void Init(s32 release_to_os_interval_ms) {
>> + void Init(s32 release_to_os_interval_ms, uptr heap_start = 0) {
>> + CHECK(!heap_start);
>> possible_regions.Init();
>> internal_memset(size_class_info_array, 0, sizeof(size_class_info_array));
>> }
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_primary64.h b/libsanitizer/sanitizer_common/sanitizer_allocator_primary64.h
>> index 0a18b0c58ef..db30e138154 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_allocator_primary64.h
>> +++ b/libsanitizer/sanitizer_common/sanitizer_allocator_primary64.h
>> @@ -19,7 +19,7 @@ template<class SizeClassAllocator> struct SizeClassAllocator64LocalCache;
>> // The template parameter Params is a class containing the actual parameters.
>> //
>> // Space: a portion of address space of kSpaceSize bytes starting at SpaceBeg.
>> -// If kSpaceBeg is ~0 then SpaceBeg is chosen dynamically my mmap.
>> +// If kSpaceBeg is ~0 then SpaceBeg is chosen dynamically by mmap.
>> // Otherwise SpaceBeg=kSpaceBeg (fixed address).
>> // kSpaceSize is a power of two.
>> // At the beginning the entire space is mprotect-ed, then small parts of it
>> @@ -69,25 +69,45 @@ class SizeClassAllocator64 {
>> return base + (static_cast<uptr>(ptr32) << kCompactPtrScale);
>> }
>>
>> - void Init(s32 release_to_os_interval_ms) {
>> + // If heap_start is nonzero, assumes kSpaceSize bytes are already mapped R/W
>> + // at heap_start and places the heap there. This mode requires kSpaceBeg ==
>> + // ~(uptr)0.
>> + void Init(s32 release_to_os_interval_ms, uptr heap_start = 0) {
>> uptr TotalSpaceSize = kSpaceSize + AdditionalSize();
>> - if (kUsingConstantSpaceBeg) {
>> - CHECK(IsAligned(kSpaceBeg, SizeClassMap::kMaxSize));
>> - CHECK_EQ(kSpaceBeg, address_range.Init(TotalSpaceSize,
>> - PrimaryAllocatorName, kSpaceBeg));
>> + PremappedHeap = heap_start != 0;
>> + if (PremappedHeap) {
>> + CHECK(!kUsingConstantSpaceBeg);
>> + NonConstSpaceBeg = heap_start;
>> + uptr RegionInfoSize = AdditionalSize();
>> + RegionInfoSpace =
>> + address_range.Init(RegionInfoSize, PrimaryAllocatorName);
>> + CHECK_NE(RegionInfoSpace, ~(uptr)0);
>> + CHECK_EQ(RegionInfoSpace,
>> + address_range.MapOrDie(RegionInfoSpace, RegionInfoSize,
>> + "SizeClassAllocator: region info"));
>> + MapUnmapCallback().OnMap(RegionInfoSpace, RegionInfoSize);
>> } else {
>> - // Combined allocator expects that an 2^N allocation is always aligned to
>> - // 2^N. For this to work, the start of the space needs to be aligned as
>> - // high as the largest size class (which also needs to be a power of 2).
>> - NonConstSpaceBeg = address_range.InitAligned(
>> - TotalSpaceSize, SizeClassMap::kMaxSize, PrimaryAllocatorName);
>> - CHECK_NE(NonConstSpaceBeg, ~(uptr)0);
>> + if (kUsingConstantSpaceBeg) {
>> + CHECK(IsAligned(kSpaceBeg, SizeClassMap::kMaxSize));
>> + CHECK_EQ(kSpaceBeg,
>> + address_range.Init(TotalSpaceSize, PrimaryAllocatorName,
>> + kSpaceBeg));
>> + } else {
>> + // Combined allocator expects that an 2^N allocation is always aligned
>> + // to 2^N. For this to work, the start of the space needs to be aligned
>> + // as high as the largest size class (which also needs to be a power of
>> + // 2).
>> + NonConstSpaceBeg = address_range.InitAligned(
>> + TotalSpaceSize, SizeClassMap::kMaxSize, PrimaryAllocatorName);
>> + CHECK_NE(NonConstSpaceBeg, ~(uptr)0);
>> + }
>> + RegionInfoSpace = SpaceEnd();
>> + MapWithCallbackOrDie(RegionInfoSpace, AdditionalSize(),
>> + "SizeClassAllocator: region info");
>> }
>> SetReleaseToOSIntervalMs(release_to_os_interval_ms);
>> - MapWithCallbackOrDie(SpaceEnd(), AdditionalSize(),
>> - "SizeClassAllocator: region info");
>> // Check that the RegionInfo array is aligned on the CacheLine size.
>> - DCHECK_EQ(SpaceEnd() % kCacheLineSize, 0);
>> + DCHECK_EQ(RegionInfoSpace % kCacheLineSize, 0);
>> }
>>
>> s32 ReleaseToOSIntervalMs() const {
>> @@ -144,6 +164,17 @@ class SizeClassAllocator64 {
>> CompactPtrT *free_array = GetFreeArray(region_beg);
>>
>> BlockingMutexLock l(®ion->mutex);
>> +#if SANITIZER_WINDOWS
>> + /* On Windows unmapping of memory during __sanitizer_purge_allocator is
>> + explicit and immediate, so unmapped regions must be explicitly mapped back
>> + in when they are accessed again. */
>> + if (region->rtoi.last_released_bytes > 0) {
>> + MmapFixedOrDie(region_beg, region->mapped_user,
>> + "SizeClassAllocator: region data");
>> + region->rtoi.n_freed_at_last_release = 0;
>> + region->rtoi.last_released_bytes = 0;
>> + }
>> +#endif
>> if (UNLIKELY(region->num_freed_chunks < n_chunks)) {
>> if (UNLIKELY(!PopulateFreeArray(stat, class_id, region,
>> n_chunks - region->num_freed_chunks)))
>> @@ -360,8 +391,7 @@ class SizeClassAllocator64 {
>> }
>> ~PackedCounterArray() {
>> if (buffer) {
>> - memory_mapper->UnmapPackedCounterArrayBuffer(
>> - reinterpret_cast<uptr>(buffer), buffer_size);
>> + memory_mapper->UnmapPackedCounterArrayBuffer(buffer, buffer_size);
>> }
>> }
>>
>> @@ -586,6 +616,11 @@ class SizeClassAllocator64 {
>>
>> atomic_sint32_t release_to_os_interval_ms_;
>>
>> + uptr RegionInfoSpace;
>> +
>> + // True if the user has already mapped the entire heap R/W.
>> + bool PremappedHeap;
>> +
>> struct Stats {
>> uptr n_allocated;
>> uptr n_freed;
>> @@ -615,7 +650,7 @@ class SizeClassAllocator64 {
>>
>> RegionInfo *GetRegionInfo(uptr class_id) const {
>> DCHECK_LT(class_id, kNumClasses);
>> - RegionInfo *regions = reinterpret_cast<RegionInfo *>(SpaceEnd());
>> + RegionInfo *regions = reinterpret_cast<RegionInfo *>(RegionInfoSpace);
>> return ®ions[class_id];
>> }
>>
>> @@ -640,6 +675,9 @@ class SizeClassAllocator64 {
>> }
>>
>> bool MapWithCallback(uptr beg, uptr size, const char *name) {
>> + if (PremappedHeap)
>> + return beg >= NonConstSpaceBeg &&
>> + beg + size <= NonConstSpaceBeg + kSpaceSize;
>> uptr mapped = address_range.Map(beg, size, name);
>> if (UNLIKELY(!mapped))
>> return false;
>> @@ -649,11 +687,18 @@ class SizeClassAllocator64 {
>> }
>>
>> void MapWithCallbackOrDie(uptr beg, uptr size, const char *name) {
>> + if (PremappedHeap) {
>> + CHECK_GE(beg, NonConstSpaceBeg);
>> + CHECK_LE(beg + size, NonConstSpaceBeg + kSpaceSize);
>> + return;
>> + }
>> CHECK_EQ(beg, address_range.MapOrDie(beg, size, name));
>> MapUnmapCallback().OnMap(beg, size);
>> }
>>
>> void UnmapWithCallbackOrDie(uptr beg, uptr size) {
>> + if (PremappedHeap)
>> + return;
>> MapUnmapCallback().OnUnmap(beg, size);
>> address_range.Unmap(beg, size);
>> }
>> @@ -792,17 +837,16 @@ class SizeClassAllocator64 {
>> return released_bytes;
>> }
>>
>> - uptr MapPackedCounterArrayBuffer(uptr buffer_size) {
>> + void *MapPackedCounterArrayBuffer(uptr buffer_size) {
>> // TODO(alekseyshl): The idea to explore is to check if we have enough
>> // space between num_freed_chunks*sizeof(CompactPtrT) and
>> // mapped_free_array to fit buffer_size bytes and use that space instead
>> // of mapping a temporary one.
>> - return reinterpret_cast<uptr>(
>> - MmapOrDieOnFatalError(buffer_size, "ReleaseToOSPageCounters"));
>> + return MmapOrDieOnFatalError(buffer_size, "ReleaseToOSPageCounters");
>> }
>>
>> - void UnmapPackedCounterArrayBuffer(uptr buffer, uptr buffer_size) {
>> - UnmapOrDie(reinterpret_cast<void *>(buffer), buffer_size);
>> + void UnmapPackedCounterArrayBuffer(void *buffer, uptr buffer_size) {
>> + UnmapOrDie(buffer, buffer_size);
>> }
>>
>> // Releases [from, to) range of pages back to OS.
>> @@ -823,6 +867,9 @@ class SizeClassAllocator64 {
>>
>> // Attempts to release RAM occupied by freed chunks back to OS. The region is
>> // expected to be locked.
>> + //
>> + // TODO(morehouse): Support a callback on memory release so HWASan can release
>> + // aliases as well.
>> void MaybeReleaseToOS(uptr class_id, bool force) {
>> RegionInfo *region = GetRegionInfo(class_id);
>> const uptr chunk_size = ClassIdToSize(class_id);
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_size_class_map.h b/libsanitizer/sanitizer_common/sanitizer_allocator_size_class_map.h
>> index 12d8c892307..c50d13303ed 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_allocator_size_class_map.h
>> +++ b/libsanitizer/sanitizer_common/sanitizer_allocator_size_class_map.h
>> @@ -24,7 +24,7 @@
>> // E.g. with kNumBits==3 all size classes after 2^kMidSizeLog
>> // look like 0b1xx0..0, where x is either 0 or 1.
>> //
>> -// Example: kNumBits=3, kMidSizeLog=4, kMidSizeLog=8, kMaxSizeLog=17:
>> +// Example: kNumBits=3, kMinSizeLog=4, kMidSizeLog=8, kMaxSizeLog=17:
>> //
>> // Classes 1 - 16 correspond to sizes 16 to 256 (size = class_id * 16).
>> // Next 4 classes: 256 + i * 64 (i = 1 to 4).
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_atomic_clang_mips.h b/libsanitizer/sanitizer_common/sanitizer_atomic_clang_mips.h
>> index 59155e9883e..2b39097112d 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_atomic_clang_mips.h
>> +++ b/libsanitizer/sanitizer_common/sanitizer_atomic_clang_mips.h
>> @@ -41,7 +41,7 @@ inline atomic_uint64_t::Type atomic_fetch_add(volatile atomic_uint64_t *ptr,
>> atomic_uint64_t::Type val,
>> memory_order mo) {
>> DCHECK(mo &
>> - (memory_order_relaxed | memory_order_releasae | memory_order_seq_cst));
>> + (memory_order_relaxed | memory_order_release | memory_order_seq_cst));
>> DCHECK(!((uptr)ptr % sizeof(*ptr)));
>>
>> atomic_uint64_t::Type ret;
>> @@ -67,7 +67,7 @@ inline bool atomic_compare_exchange_strong(volatile atomic_uint64_t *ptr,
>> atomic_uint64_t::Type xchg,
>> memory_order mo) {
>> DCHECK(mo &
>> - (memory_order_relaxed | memory_order_releasae | memory_order_seq_cst));
>> + (memory_order_relaxed | memory_order_release | memory_order_seq_cst));
>> DCHECK(!((uptr)ptr % sizeof(*ptr)));
>>
>> typedef atomic_uint64_t::Type Type;
>> @@ -90,7 +90,7 @@ template <>
>> inline atomic_uint64_t::Type atomic_load(const volatile atomic_uint64_t *ptr,
>> memory_order mo) {
>> DCHECK(mo &
>> - (memory_order_relaxed | memory_order_releasae | memory_order_seq_cst));
>> + (memory_order_relaxed | memory_order_release | memory_order_seq_cst));
>> DCHECK(!((uptr)ptr % sizeof(*ptr)));
>>
>> atomic_uint64_t::Type zero = 0;
>> @@ -103,7 +103,7 @@ template <>
>> inline void atomic_store(volatile atomic_uint64_t *ptr, atomic_uint64_t::Type v,
>> memory_order mo) {
>> DCHECK(mo &
>> - (memory_order_relaxed | memory_order_releasae | memory_order_seq_cst));
>> + (memory_order_relaxed | memory_order_release | memory_order_seq_cst));
>> DCHECK(!((uptr)ptr % sizeof(*ptr)));
>>
>> __spin_lock(&lock.lock);
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_chained_origin_depot.cpp b/libsanitizer/sanitizer_common/sanitizer_chained_origin_depot.cpp
>> new file mode 100644
>> index 00000000000..250ac39e130
>> --- /dev/null
>> +++ b/libsanitizer/sanitizer_common/sanitizer_chained_origin_depot.cpp
>> @@ -0,0 +1,108 @@
>> +//===-- sanitizer_chained_origin_depot.cpp --------------------------------===//
>> +//
>> +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
>> +// See https://llvm.org/LICENSE.txt for license information.
>> +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
>> +//
>> +//===----------------------------------------------------------------------===//
>> +//
>> +// A storage for chained origins.
>> +//===----------------------------------------------------------------------===//
>> +
>> +#include "sanitizer_chained_origin_depot.h"
>> +
>> +namespace __sanitizer {
>> +
>> +bool ChainedOriginDepot::ChainedOriginDepotNode::eq(
>> + u32 hash, const args_type &args) const {
>> + return here_id == args.here_id && prev_id == args.prev_id;
>> +}
>> +
>> +uptr ChainedOriginDepot::ChainedOriginDepotNode::storage_size(
>> + const args_type &args) {
>> + return sizeof(ChainedOriginDepotNode);
>> +}
>> +
>> +/* This is murmur2 hash for the 64->32 bit case.
>> + It does not behave all that well because the keys have a very biased
>> + distribution (I've seen 7-element buckets with the table only 14% full).
>> +
>> + here_id is built of
>> + * (1 bits) Reserved, zero.
>> + * (8 bits) Part id = bits 13..20 of the hash value of here_id's key.
>> + * (23 bits) Sequential number (each part has each own sequence).
>> +
>> + prev_id has either the same distribution as here_id (but with 3:8:21)
>> + split, or one of two reserved values (-1) or (-2). Either case can
>> + dominate depending on the workload.
>> +*/
>> +u32 ChainedOriginDepot::ChainedOriginDepotNode::hash(const args_type &args) {
>> + const u32 m = 0x5bd1e995;
>> + const u32 seed = 0x9747b28c;
>> + const u32 r = 24;
>> + u32 h = seed;
>> + u32 k = args.here_id;
>> + k *= m;
>> + k ^= k >> r;
>> + k *= m;
>> + h *= m;
>> + h ^= k;
>> +
>> + k = args.prev_id;
>> + k *= m;
>> + k ^= k >> r;
>> + k *= m;
>> + h *= m;
>> + h ^= k;
>> +
>> + h ^= h >> 13;
>> + h *= m;
>> + h ^= h >> 15;
>> + return h;
>> +}
>> +
>> +bool ChainedOriginDepot::ChainedOriginDepotNode::is_valid(
>> + const args_type &args) {
>> + return true;
>> +}
>> +
>> +void ChainedOriginDepot::ChainedOriginDepotNode::store(const args_type &args,
>> + u32 other_hash) {
>> + here_id = args.here_id;
>> + prev_id = args.prev_id;
>> +}
>> +
>> +ChainedOriginDepot::ChainedOriginDepotNode::args_type
>> +ChainedOriginDepot::ChainedOriginDepotNode::load() const {
>> + args_type ret = {here_id, prev_id};
>> + return ret;
>> +}
>> +
>> +ChainedOriginDepot::ChainedOriginDepotNode::Handle
>> +ChainedOriginDepot::ChainedOriginDepotNode::get_handle() {
>> + return Handle(this);
>> +}
>> +
>> +ChainedOriginDepot::ChainedOriginDepot() {}
>> +
>> +StackDepotStats *ChainedOriginDepot::GetStats() { return depot.GetStats(); }
>> +
>> +bool ChainedOriginDepot::Put(u32 here_id, u32 prev_id, u32 *new_id) {
>> + ChainedOriginDepotDesc desc = {here_id, prev_id};
>> + bool inserted;
>> + ChainedOriginDepotNode::Handle h = depot.Put(desc, &inserted);
>> + *new_id = h.valid() ? h.id() : 0;
>> + return inserted;
>> +}
>> +
>> +u32 ChainedOriginDepot::Get(u32 id, u32 *other) {
>> + ChainedOriginDepotDesc desc = depot.Get(id);
>> + *other = desc.prev_id;
>> + return desc.here_id;
>> +}
>> +
>> +void ChainedOriginDepot::LockAll() { depot.LockAll(); }
>> +
>> +void ChainedOriginDepot::UnlockAll() { depot.UnlockAll(); }
>> +
>> +} // namespace __sanitizer
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_chained_origin_depot.h b/libsanitizer/sanitizer_common/sanitizer_chained_origin_depot.h
>> new file mode 100644
>> index 00000000000..453cdf6b544
>> --- /dev/null
>> +++ b/libsanitizer/sanitizer_common/sanitizer_chained_origin_depot.h
>> @@ -0,0 +1,88 @@
>> +//===-- sanitizer_chained_origin_depot.h ------------------------*- C++ -*-===//
>> +//
>> +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
>> +// See https://llvm.org/LICENSE.txt for license information.
>> +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
>> +//
>> +//===----------------------------------------------------------------------===//
>> +//
>> +// A storage for chained origins.
>> +//===----------------------------------------------------------------------===//
>> +
>> +#ifndef SANITIZER_CHAINED_ORIGIN_DEPOT_H
>> +#define SANITIZER_CHAINED_ORIGIN_DEPOT_H
>> +
>> +#include "sanitizer_common.h"
>> +#include "sanitizer_stackdepotbase.h"
>> +
>> +namespace __sanitizer {
>> +
>> +class ChainedOriginDepot {
>> + public:
>> + ChainedOriginDepot();
>> +
>> + // Gets the statistic of the origin chain storage.
>> + StackDepotStats *GetStats();
>> +
>> + // Stores a chain with StackDepot ID here_id and previous chain ID prev_id.
>> + // If successful, returns true and the new chain id new_id.
>> + // If the same element already exists, returns false and sets new_id to the
>> + // existing ID.
>> + bool Put(u32 here_id, u32 prev_id, u32 *new_id);
>> +
>> + // Retrieves the stored StackDepot ID for the given origin ID.
>> + u32 Get(u32 id, u32 *other);
>> +
>> + void LockAll();
>> + void UnlockAll();
>> +
>> + private:
>> + struct ChainedOriginDepotDesc {
>> + u32 here_id;
>> + u32 prev_id;
>> + };
>> +
>> + struct ChainedOriginDepotNode {
>> + ChainedOriginDepotNode *link;
>> + u32 id;
>> + u32 here_id;
>> + u32 prev_id;
>> +
>> + typedef ChainedOriginDepotDesc args_type;
>> +
>> + bool eq(u32 hash, const args_type &args) const;
>> +
>> + static uptr storage_size(const args_type &args);
>> +
>> + static u32 hash(const args_type &args);
>> +
>> + static bool is_valid(const args_type &args);
>> +
>> + void store(const args_type &args, u32 other_hash);
>> +
>> + args_type load() const;
>> +
>> + struct Handle {
>> + ChainedOriginDepotNode *node_;
>> + Handle() : node_(nullptr) {}
>> + explicit Handle(ChainedOriginDepotNode *node) : node_(node) {}
>> + bool valid() { return node_; }
>> + u32 id() { return node_->id; }
>> + int here_id() { return node_->here_id; }
>> + int prev_id() { return node_->prev_id; }
>> + };
>> +
>> + Handle get_handle();
>> +
>> + typedef Handle handle_type;
>> + };
>> +
>> + StackDepotBase<ChainedOriginDepotNode, 4, 20> depot;
>> +
>> + ChainedOriginDepot(const ChainedOriginDepot &) = delete;
>> + void operator=(const ChainedOriginDepot &) = delete;
>> +};
>> +
>> +} // namespace __sanitizer
>> +
>> +#endif // SANITIZER_CHAINED_ORIGIN_DEPOT_H
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_common.cpp b/libsanitizer/sanitizer_common/sanitizer_common.cpp
>> index 87efda5bd37..33960d94a2f 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_common.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_common.cpp
>> @@ -87,7 +87,7 @@ const char *StripModuleName(const char *module) {
>> void ReportErrorSummary(const char *error_message, const char *alt_tool_name) {
>> if (!common_flags()->print_summary)
>> return;
>> - InternalScopedString buff(kMaxSummaryLength);
>> + InternalScopedString buff;
>> buff.append("SUMMARY: %s: %s",
>> alt_tool_name ? alt_tool_name : SanitizerToolName, error_message);
>> __sanitizer_report_error_summary(buff.data());
>> @@ -274,6 +274,14 @@ uptr ReadBinaryNameCached(/*out*/char *buf, uptr buf_len) {
>> return name_len;
>> }
>>
>> +uptr ReadBinaryDir(/*out*/ char *buf, uptr buf_len) {
>> + ReadBinaryNameCached(buf, buf_len);
>> + const char *exec_name_pos = StripModuleName(buf);
>> + uptr name_len = exec_name_pos - buf;
>> + buf[name_len] = '\0';
>> + return name_len;
>> +}
>> +
>> #if !SANITIZER_GO
>> void PrintCmdline() {
>> char **argv = GetArgv();
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_common.h b/libsanitizer/sanitizer_common/sanitizer_common.h
>> index bce24d68045..7b65dd7dfb8 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_common.h
>> +++ b/libsanitizer/sanitizer_common/sanitizer_common.h
>> @@ -44,7 +44,7 @@ const uptr kMaxPathLength = 4096;
>>
>> const uptr kMaxThreadStackSize = 1 << 30; // 1Gb
>>
>> -static const uptr kErrorMessageBufferSize = 1 << 16;
>> +const uptr kErrorMessageBufferSize = 1 << 16;
>>
>> // Denotes fake PC values that come from JIT/JAVA/etc.
>> // For such PC values __tsan_symbolize_external_ex() will be called.
>> @@ -135,6 +135,15 @@ void UnmapFromTo(uptr from, uptr to);
>> uptr MapDynamicShadow(uptr shadow_size_bytes, uptr shadow_scale,
>> uptr min_shadow_base_alignment, uptr &high_mem_end);
>>
>> +// Let S = max(shadow_size, num_aliases * alias_size, ring_buffer_size).
>> +// Reserves 2*S bytes of address space to the right of the returned address and
>> +// ring_buffer_size bytes to the left. The returned address is aligned to 2*S.
>> +// Also creates num_aliases regions of accessible memory starting at offset S
>> +// from the returned address. Each region has size alias_size and is backed by
>> +// the same physical memory.
>> +uptr MapDynamicShadowAndAliases(uptr shadow_size, uptr alias_size,
>> + uptr num_aliases, uptr ring_buffer_size);
>> +
>> // Reserve memory range [beg, end]. If madvise_shadow is true then apply
>> // madvise (e.g. hugepages, core dumping) requested by options.
>> void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name,
>> @@ -248,6 +257,7 @@ const char *StripModuleName(const char *module);
>> // OS
>> uptr ReadBinaryName(/*out*/char *buf, uptr buf_len);
>> uptr ReadBinaryNameCached(/*out*/char *buf, uptr buf_len);
>> +uptr ReadBinaryDir(/*out*/ char *buf, uptr buf_len);
>> uptr ReadLongProcessName(/*out*/ char *buf, uptr buf_len);
>> const char *GetProcessName();
>> void UpdateProcessName();
>> @@ -294,8 +304,8 @@ void NORETURN ReportMmapFailureAndDie(uptr size, const char *mem_type,
>> const char *mmap_type, error_t err,
>> bool raw_report = false);
>>
>> -// Specific tools may override behavior of "Die" and "CheckFailed" functions
>> -// to do tool-specific job.
>> +// Specific tools may override behavior of "Die" function to do tool-specific
>> +// job.
>> typedef void (*DieCallbackType)(void);
>>
>> // It's possible to add several callbacks that would be run when "Die" is
>> @@ -307,9 +317,7 @@ bool RemoveDieCallback(DieCallbackType callback);
>>
>> void SetUserDieCallback(DieCallbackType callback);
>>
>> -typedef void (*CheckFailedCallbackType)(const char *, int, const char *,
>> - u64, u64);
>> -void SetCheckFailedCallback(CheckFailedCallbackType callback);
>> +void SetCheckUnwindCallback(void (*callback)());
>>
>> // Callback will be called if soft_rss_limit_mb is given and the limit is
>> // exceeded (exceeded==true) or if rss went down below the limit
>> @@ -343,8 +351,6 @@ void ReportDeadlySignal(const SignalContext &sig, u32 tid,
>> void SetAlternateSignalStack();
>> void UnsetAlternateSignalStack();
>>
>> -// 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.
>> @@ -441,8 +447,14 @@ inline uptr Log2(uptr x) {
>>
>> // Don't use std::min, std::max or std::swap, to minimize dependency
>> // on libstdc++.
>> -template<class T> T Min(T a, T b) { return a < b ? a : b; }
>> -template<class T> T Max(T a, T b) { return a > b ? a : b; }
>> +template <class T>
>> +constexpr T Min(T a, T b) {
>> + return a < b ? a : b;
>> +}
>> +template <class T>
>> +constexpr T Max(T a, T b) {
>> + return a > b ? a : b;
>> +}
>> template<class T> void Swap(T& a, T& b) {
>> T tmp = a;
>> a = b;
>> @@ -467,6 +479,7 @@ inline int ToLower(int c) {
>> template<typename T>
>> class InternalMmapVectorNoCtor {
>> public:
>> + using value_type = T;
>> void Initialize(uptr initial_capacity) {
>> capacity_bytes_ = 0;
>> size_ = 0;
>> @@ -590,21 +603,21 @@ class InternalMmapVector : public InternalMmapVectorNoCtor<T> {
>> InternalMmapVector &operator=(InternalMmapVector &&) = delete;
>> };
>>
>> -class InternalScopedString : public InternalMmapVector<char> {
>> +class InternalScopedString {
>> public:
>> - explicit InternalScopedString(uptr max_length)
>> - : InternalMmapVector<char>(max_length), length_(0) {
>> - (*this)[0] = '\0';
>> - }
>> - uptr length() { return length_; }
>> + InternalScopedString() : buffer_(1) { buffer_[0] = '\0'; }
>> +
>> + uptr length() const { return buffer_.size() - 1; }
>> void clear() {
>> - (*this)[0] = '\0';
>> - length_ = 0;
>> + buffer_.resize(1);
>> + buffer_[0] = '\0';
>> }
>> void append(const char *format, ...);
>> + const char *data() const { return buffer_.data(); }
>> + char *data() { return buffer_.data(); }
>>
>> private:
>> - uptr length_;
>> + InternalMmapVector<char> buffer_;
>> };
>>
>> template <class T>
>> @@ -651,9 +664,13 @@ void Sort(T *v, uptr size, Compare comp = {}) {
>>
>> // Works like std::lower_bound: finds the first element that is not less
>> // than the val.
>> -template <class Container, class Value, class Compare>
>> -uptr InternalLowerBound(const Container &v, uptr first, uptr last,
>> - const Value &val, Compare comp) {
>> +template <class Container,
>> + class Compare = CompareLess<typename Container::value_type>>
>> +uptr InternalLowerBound(const Container &v,
>> + const typename Container::value_type &val,
>> + Compare comp = {}) {
>> + uptr first = 0;
>> + uptr last = v.size();
>> while (last > first) {
>> uptr mid = (first + last) / 2;
>> if (comp(v[mid], val))
>> @@ -677,6 +694,27 @@ enum ModuleArch {
>> kModuleArchRISCV64
>> };
>>
>> +// Sorts and removes duplicates from the container.
>> +template <class Container,
>> + class Compare = CompareLess<typename Container::value_type>>
>> +void SortAndDedup(Container &v, Compare comp = {}) {
>> + Sort(v.data(), v.size(), comp);
>> + uptr size = v.size();
>> + if (size < 2)
>> + return;
>> + uptr last = 0;
>> + for (uptr i = 1; i < size; ++i) {
>> + if (comp(v[last], v[i])) {
>> + ++last;
>> + if (last != i)
>> + v[last] = v[i];
>> + } else {
>> + CHECK(!comp(v[i], v[last]));
>> + }
>> + }
>> + v.resize(last + 1);
>> +}
>> +
>> // Opens the file 'file_name" and reads up to 'max_len' bytes.
>> // The resulting buffer is mmaped and stored in '*buff'.
>> // Returns true if file was successfully opened and read.
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc b/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc
>> index 2f2787e283a..7867fccde39 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc
>> +++ b/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc
>> @@ -239,7 +239,7 @@ extern const short *_tolower_tab_;
>> COMMON_INTERCEPT_FUNCTION(fn)
>> #endif
>>
>> -#ifdef __GLIBC__
>> +#if SANITIZER_GLIBC
>> // If we could not find the versioned symbol, fall back to an unversioned
>> // lookup. This is needed to work around a GLibc bug that causes dlsym
>> // with RTLD_NEXT to return the oldest versioned symbol.
>> @@ -2195,6 +2195,7 @@ INTERCEPTOR(int, clock_gettime, u32 clk_id, void *tp) {
>> }
>> return res;
>> }
>> +#if SANITIZER_GLIBC
>> namespace __sanitizer {
>> extern "C" {
>> int real_clock_gettime(u32 clk_id, void *tp) {
>> @@ -2204,6 +2205,7 @@ int real_clock_gettime(u32 clk_id, void *tp) {
>> }
>> } // extern "C"
>> } // namespace __sanitizer
>> +#endif
>> INTERCEPTOR(int, clock_settime, u32 clk_id, const void *tp) {
>> void *ctx;
>> COMMON_INTERCEPTOR_ENTER(ctx, clock_settime, clk_id, tp);
>> @@ -3355,7 +3357,7 @@ INTERCEPTOR(char *, setlocale, int category, char *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);
>> + COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, REAL(strlen)(res) + 1);
>> unpoison_ctype_arrays(ctx);
>> }
>> return res;
>> @@ -4030,7 +4032,7 @@ INTERCEPTOR(int, sigwait, __sanitizer_sigset_t *set, int *sig) {
>> // FIXME: under ASan the call below may write to freed memory and corrupt
>> // its metadata. See
>> // https://github.com/google/sanitizers/issues/321.
>> - int res = REAL(sigwait)(set, sig);
>> + int res = COMMON_INTERCEPTOR_BLOCK_REAL(sigwait)(set, sig);
>> if (!res && sig) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sig, sizeof(*sig));
>> return res;
>> }
>> @@ -4047,7 +4049,7 @@ INTERCEPTOR(int, sigwaitinfo, __sanitizer_sigset_t *set, void *info) {
>> // FIXME: under ASan the call below may write to freed memory and corrupt
>> // its metadata. See
>> // https://github.com/google/sanitizers/issues/321.
>> - int res = REAL(sigwaitinfo)(set, info);
>> + int res = COMMON_INTERCEPTOR_BLOCK_REAL(sigwaitinfo)(set, info);
>> if (res > 0 && info) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, info, siginfo_t_sz);
>> return res;
>> }
>> @@ -4066,7 +4068,7 @@ INTERCEPTOR(int, sigtimedwait, __sanitizer_sigset_t *set, void *info,
>> // FIXME: under ASan the call below may write to freed memory and corrupt
>> // its metadata. See
>> // https://github.com/google/sanitizers/issues/321.
>> - int res = REAL(sigtimedwait)(set, info, timeout);
>> + int res = COMMON_INTERCEPTOR_BLOCK_REAL(sigtimedwait)(set, info, timeout);
>> if (res > 0 && info) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, info, siginfo_t_sz);
>> return res;
>> }
>> @@ -5995,6 +5997,9 @@ void unpoison_file(__sanitizer_FILE *fp) {
>> if (fp->_IO_read_base && fp->_IO_read_base < fp->_IO_read_end)
>> COMMON_INTERCEPTOR_INITIALIZE_RANGE(fp->_IO_read_base,
>> fp->_IO_read_end - fp->_IO_read_base);
>> + if (fp->_IO_write_base && fp->_IO_write_base < fp->_IO_write_end)
>> + COMMON_INTERCEPTOR_INITIALIZE_RANGE(fp->_IO_write_base,
>> + fp->_IO_write_end - fp->_IO_write_base);
>> #endif
>> #endif // SANITIZER_HAS_STRUCT_FILE
>> }
>> @@ -6221,6 +6226,8 @@ INTERCEPTOR(void, _obstack_newchunk, __sanitizer_obstack *obstack, int length) {
>> INTERCEPTOR(int, fflush, __sanitizer_FILE *fp) {
>> void *ctx;
>> COMMON_INTERCEPTOR_ENTER(ctx, fflush, fp);
>> + if (fp)
>> + unpoison_file(fp);
>> int res = REAL(fflush)(fp);
>> // FIXME: handle fp == NULL
>> if (fp) {
>> @@ -6240,6 +6247,8 @@ INTERCEPTOR(int, fclose, __sanitizer_FILE *fp) {
>> COMMON_INTERCEPTOR_ENTER(ctx, fclose, fp);
>> COMMON_INTERCEPTOR_FILE_CLOSE(ctx, fp);
>> const FileMetadata *m = GetInterceptorMetadata(fp);
>> + if (fp)
>> + unpoison_file(fp);
>> int res = REAL(fclose)(fp);
>> if (m) {
>> COMMON_INTERCEPTOR_INITIALIZE_RANGE(*m->addr, *m->size);
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_common_interceptors_ioctl.inc b/libsanitizer/sanitizer_common/sanitizer_common_interceptors_ioctl.inc
>> index 490a04b2181..7f181258eab 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_common_interceptors_ioctl.inc
>> +++ b/libsanitizer/sanitizer_common/sanitizer_common_interceptors_ioctl.inc
>> @@ -330,13 +330,17 @@ static void ioctl_table_fill() {
>> _(SOUND_PCM_WRITE_CHANNELS, WRITE, sizeof(int));
>> _(SOUND_PCM_WRITE_FILTER, WRITE, sizeof(int));
>> _(TCFLSH, NONE, 0);
>> +#if SANITIZER_GLIBC
>> _(TCGETA, WRITE, struct_termio_sz);
>> +#endif
>> _(TCGETS, WRITE, struct_termios_sz);
>> _(TCSBRK, NONE, 0);
>> _(TCSBRKP, NONE, 0);
>> +#if SANITIZER_GLIBC
>> _(TCSETA, READ, struct_termio_sz);
>> _(TCSETAF, READ, struct_termio_sz);
>> _(TCSETAW, READ, struct_termio_sz);
>> +#endif
>> _(TCSETS, READ, struct_termios_sz);
>> _(TCSETSF, READ, struct_termios_sz);
>> _(TCSETSW, READ, struct_termios_sz);
>> @@ -364,7 +368,7 @@ static void ioctl_table_fill() {
>> _(VT_WAITACTIVE, NONE, 0);
>> #endif
>>
>> -#if SANITIZER_LINUX && !SANITIZER_ANDROID
>> +#if SANITIZER_GLIBC
>> // _(SIOCDEVPLIP, WRITE, struct_ifreq_sz); // the same as EQL_ENSLAVE
>> _(CYGETDEFTHRESH, WRITE, sizeof(int));
>> _(CYGETDEFTIMEOUT, WRITE, sizeof(int));
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_common_interceptors_vfork_aarch64.inc.S b/libsanitizer/sanitizer_common/sanitizer_common_interceptors_vfork_aarch64.inc.S
>> index 20f42f1ea94..72e482754b6 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_common_interceptors_vfork_aarch64.inc.S
>> +++ b/libsanitizer/sanitizer_common/sanitizer_common_interceptors_vfork_aarch64.inc.S
>> @@ -1,6 +1,7 @@
>> #if defined(__aarch64__) && defined(__linux__)
>>
>> #include "sanitizer_common/sanitizer_asm.h"
>> +#include "builtins/assembly.h"
>>
>> ASM_HIDDEN(COMMON_INTERCEPTOR_SPILL_AREA)
>>
>> @@ -9,6 +10,7 @@ ASM_HIDDEN(COMMON_INTERCEPTOR_SPILL_AREA)
>> ASM_TYPE_FUNCTION(ASM_WRAPPER_NAME(vfork))
>> ASM_WRAPPER_NAME(vfork):
>> // Save x30 in the off-stack spill area.
>> + hint #25 // paciasp
>> stp xzr, x30, [sp, #-16]!
>> bl COMMON_INTERCEPTOR_SPILL_AREA
>> ldp xzr, x30, [sp], 16
>> @@ -33,6 +35,7 @@ ASM_WRAPPER_NAME(vfork):
>> bl COMMON_INTERCEPTOR_SPILL_AREA
>> ldr x30, [x0]
>> ldp x0, xzr, [sp], 16
>> + hint #29 // autiasp
>>
>> ret
>> ASM_SIZE(vfork)
>> @@ -40,4 +43,6 @@ ASM_SIZE(vfork)
>> .weak vfork
>> .set vfork, ASM_WRAPPER_NAME(vfork)
>>
>> +GNU_PROPERTY_BTI_PAC
>> +
>> #endif
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_common_interface.inc b/libsanitizer/sanitizer_common/sanitizer_common_interface.inc
>> index c78b6e10b68..932e5478616 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_common_interface.inc
>> +++ b/libsanitizer/sanitizer_common/sanitizer_common_interface.inc
>> @@ -13,6 +13,7 @@ INTERFACE_FUNCTION(__sanitizer_contiguous_container_find_bad_address)
>> INTERFACE_FUNCTION(__sanitizer_set_death_callback)
>> INTERFACE_FUNCTION(__sanitizer_set_report_path)
>> INTERFACE_FUNCTION(__sanitizer_set_report_fd)
>> +INTERFACE_FUNCTION(__sanitizer_get_report_path)
>> INTERFACE_FUNCTION(__sanitizer_verify_contiguous_container)
>> INTERFACE_WEAK_FUNCTION(__sanitizer_on_print)
>> INTERFACE_WEAK_FUNCTION(__sanitizer_report_error_summary)
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_common_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_common_libcdep.cpp
>> index 047c5a17ea6..1037938f3d3 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_common_libcdep.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_common_libcdep.cpp
>> @@ -92,14 +92,13 @@ void *BackgroundThread(void *arg) {
>> #endif
>>
>> void WriteToSyslog(const char *msg) {
>> - InternalScopedString msg_copy(kErrorMessageBufferSize);
>> + InternalScopedString msg_copy;
>> msg_copy.append("%s", msg);
>> - char *p = msg_copy.data();
>> - char *q;
>> + const char *p = msg_copy.data();
>>
>> // Print one line at a time.
>> // syslog, at least on Android, has an implicit message length limit.
>> - while ((q = internal_strchr(p, '\n'))) {
>> + while (char* q = internal_strchr(p, '\n')) {
>> *q = '\0';
>> WriteOneLineToSyslog(p);
>> p = q + 1;
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_file.cpp b/libsanitizer/sanitizer_common/sanitizer_file.cpp
>> index 7cce60906b7..0b92dccde4a 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_file.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_file.cpp
>> @@ -58,6 +58,9 @@ void ReportFile::ReopenIfNecessary() {
>> } else {
>> internal_snprintf(full_path, kMaxPathLength, "%s.%zu", path_prefix, pid);
>> }
>> + if (common_flags()->log_suffix) {
>> + internal_strlcat(full_path, common_flags()->log_suffix, kMaxPathLength);
>> + }
>> error_t err;
>> fd = OpenFile(full_path, WrOnly, &err);
>> if (fd == kInvalidFd) {
>> @@ -95,6 +98,12 @@ void ReportFile::SetReportPath(const char *path) {
>> }
>> }
>>
>> +const char *ReportFile::GetReportPath() {
>> + SpinMutexLock l(mu);
>> + ReopenIfNecessary();
>> + return full_path;
>> +}
>> +
>> bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size,
>> uptr *read_len, uptr max_len, error_t *errno_p) {
>> *buff = nullptr;
>> @@ -213,6 +222,10 @@ void __sanitizer_set_report_fd(void *fd) {
>> report_file.fd = (fd_t)reinterpret_cast<uptr>(fd);
>> report_file.fd_pid = internal_getpid();
>> }
>> +
>> +const char *__sanitizer_get_report_path() {
>> + return report_file.GetReportPath();
>> +}
>> } // extern "C"
>>
>> #endif // !SANITIZER_FUCHSIA
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_file.h b/libsanitizer/sanitizer_common/sanitizer_file.h
>> index 26681f0493d..08671ab67d0 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_file.h
>> +++ b/libsanitizer/sanitizer_common/sanitizer_file.h
>> @@ -26,6 +26,7 @@ struct ReportFile {
>> void Write(const char *buffer, uptr length);
>> bool SupportsColors();
>> void SetReportPath(const char *path);
>> + const char *GetReportPath();
>>
>> // Don't use fields directly. They are only declared public to allow
>> // aggregate initialization.
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_flags.cpp b/libsanitizer/sanitizer_common/sanitizer_flags.cpp
>> index 21048be7304..d52e96a7c38 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_flags.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_flags.cpp
>> @@ -35,6 +35,7 @@ void CommonFlags::CopyFrom(const CommonFlags &other) {
>> // Copy the string from "s" to "out", making the following substitutions:
>> // %b = binary basename
>> // %p = pid
>> +// %d = binary directory
>> void SubstituteForFlagValue(const char *s, char *out, uptr out_size) {
>> char *out_end = out + out_size;
>> while (*s && out < out_end - 1) {
>> @@ -64,6 +65,12 @@ void SubstituteForFlagValue(const char *s, char *out, uptr out_size) {
>> s += 2; // skip "%p"
>> break;
>> }
>> + case 'd': {
>> + uptr len = ReadBinaryDir(out, out_end - out);
>> + out += len;
>> + s += 2; // skip "%d"
>> + break;
>> + }
>> default:
>> *out++ = *s++;
>> break;
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_flags.inc b/libsanitizer/sanitizer_common/sanitizer_flags.inc
>> index cfb5822645f..3bc44c6b1eb 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_flags.inc
>> +++ b/libsanitizer/sanitizer_common/sanitizer_flags.inc
>> @@ -59,6 +59,8 @@ COMMON_FLAG(
>> bool, log_exe_name, false,
>> "Mention name of executable when reporting error and "
>> "append executable name to logs (as in \"log_path.exe_name.pid\").")
>> +COMMON_FLAG(const char *, log_suffix, nullptr,
>> + "String to append to log file name, e.g. \".txt\".")
>> COMMON_FLAG(
>> bool, log_to_syslog, (bool)SANITIZER_ANDROID || (bool)SANITIZER_MAC,
>> "Write all sanitizer output to syslog in addition to other means of "
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_fuchsia.cpp b/libsanitizer/sanitizer_common/sanitizer_fuchsia.cpp
>> index 7200ffdac0f..4f692f99c20 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_fuchsia.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_fuchsia.cpp
>> @@ -14,7 +14,6 @@
>> #include "sanitizer_fuchsia.h"
>> #if SANITIZER_FUCHSIA
>>
>> -#include <limits.h>
>> #include <pthread.h>
>> #include <stdlib.h>
>> #include <unistd.h>
>> @@ -69,9 +68,7 @@ uptr internal_getpid() {
>> return pid;
>> }
>>
>> -int internal_dlinfo(void *handle, int request, void *p) {
>> - UNIMPLEMENTED();
>> -}
>> +int internal_dlinfo(void *handle, int request, void *p) { UNIMPLEMENTED(); }
>>
>> uptr GetThreadSelf() { return reinterpret_cast<uptr>(thrd_current()); }
>>
>> @@ -153,9 +150,9 @@ void BlockingMutex::CheckLocked() {
>> CHECK_NE(MtxUnlocked, atomic_load(m, memory_order_relaxed));
>> }
>>
>> -uptr GetPageSize() { return PAGE_SIZE; }
>> +uptr GetPageSize() { return _zx_system_get_page_size(); }
>>
>> -uptr GetMmapGranularity() { return PAGE_SIZE; }
>> +uptr GetMmapGranularity() { return _zx_system_get_page_size(); }
>>
>> sanitizer_shadow_bounds_t ShadowBounds;
>>
>> @@ -168,7 +165,7 @@ uptr GetMaxVirtualAddress() { return GetMaxUserVirtualAddress(); }
>>
>> static void *DoAnonymousMmapOrDie(uptr size, const char *mem_type,
>> bool raw_report, bool die_for_nomem) {
>> - size = RoundUpTo(size, PAGE_SIZE);
>> + size = RoundUpTo(size, GetPageSize());
>>
>> zx_handle_t vmo;
>> zx_status_t status = _zx_vmo_create(size, 0, &vmo);
>> @@ -214,15 +211,14 @@ void *MmapOrDieOnFatalError(uptr size, const char *mem_type) {
>>
>> uptr ReservedAddressRange::Init(uptr init_size, const char *name,
>> uptr fixed_addr) {
>> - init_size = RoundUpTo(init_size, PAGE_SIZE);
>> + init_size = RoundUpTo(init_size, GetPageSize());
>> DCHECK_EQ(os_handle_, ZX_HANDLE_INVALID);
>> uintptr_t base;
>> zx_handle_t vmar;
>> - zx_status_t status =
>> - _zx_vmar_allocate(
>> - _zx_vmar_root_self(),
>> - ZX_VM_CAN_MAP_READ | ZX_VM_CAN_MAP_WRITE | ZX_VM_CAN_MAP_SPECIFIC,
>> - 0, init_size, &vmar, &base);
>> + zx_status_t status = _zx_vmar_allocate(
>> + _zx_vmar_root_self(),
>> + ZX_VM_CAN_MAP_READ | ZX_VM_CAN_MAP_WRITE | ZX_VM_CAN_MAP_SPECIFIC, 0,
>> + init_size, &vmar, &base);
>> if (status != ZX_OK)
>> ReportMmapFailureAndDie(init_size, name, "zx_vmar_allocate", status);
>> base_ = reinterpret_cast<void *>(base);
>> @@ -236,7 +232,7 @@ uptr ReservedAddressRange::Init(uptr init_size, const char *name,
>> static uptr DoMmapFixedOrDie(zx_handle_t vmar, uptr fixed_addr, uptr map_size,
>> void *base, const char *name, bool die_for_nomem) {
>> uptr offset = fixed_addr - reinterpret_cast<uptr>(base);
>> - map_size = RoundUpTo(map_size, PAGE_SIZE);
>> + map_size = RoundUpTo(map_size, GetPageSize());
>> zx_handle_t vmo;
>> zx_status_t status = _zx_vmo_create(map_size, 0, &vmo);
>> if (status != ZX_OK) {
>> @@ -264,19 +260,19 @@ static uptr DoMmapFixedOrDie(zx_handle_t vmar, uptr fixed_addr, uptr map_size,
>>
>> uptr ReservedAddressRange::Map(uptr fixed_addr, uptr map_size,
>> const char *name) {
>> - return DoMmapFixedOrDie(os_handle_, fixed_addr, map_size, base_,
>> - name_, false);
>> + return DoMmapFixedOrDie(os_handle_, fixed_addr, map_size, base_, name_,
>> + false);
>> }
>>
>> uptr ReservedAddressRange::MapOrDie(uptr fixed_addr, uptr map_size,
>> const char *name) {
>> - return DoMmapFixedOrDie(os_handle_, fixed_addr, map_size, base_,
>> - name_, true);
>> + return DoMmapFixedOrDie(os_handle_, fixed_addr, map_size, base_, name_, true);
>> }
>>
>> void UnmapOrDieVmar(void *addr, uptr size, zx_handle_t target_vmar) {
>> - if (!addr || !size) return;
>> - size = RoundUpTo(size, PAGE_SIZE);
>> + if (!addr || !size)
>> + return;
>> + size = RoundUpTo(size, GetPageSize());
>>
>> zx_status_t status =
>> _zx_vmar_unmap(target_vmar, reinterpret_cast<uintptr_t>(addr), size);
>> @@ -316,7 +312,7 @@ void *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name) {
>>
>> void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment,
>> const char *mem_type) {
>> - CHECK_GE(size, PAGE_SIZE);
>> + CHECK_GE(size, GetPageSize());
>> CHECK(IsPowerOfTwo(size));
>> CHECK(IsPowerOfTwo(alignment));
>>
>> @@ -356,7 +352,8 @@ void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment,
>> _zx_vmar_root_self(),
>> ZX_VM_PERM_READ | ZX_VM_PERM_WRITE | ZX_VM_SPECIFIC_OVERWRITE,
>> addr - info.base, vmo, 0, size, &new_addr);
>> - if (status == ZX_OK) CHECK_EQ(new_addr, addr);
>> + if (status == ZX_OK)
>> + CHECK_EQ(new_addr, addr);
>> }
>> }
>> if (status == ZX_OK && addr != map_addr)
>> @@ -381,9 +378,18 @@ void UnmapOrDie(void *addr, uptr size) {
>> UnmapOrDieVmar(addr, size, _zx_vmar_root_self());
>> }
>>
>> -// This is used on the shadow mapping, which cannot be changed.
>> -// Zircon doesn't have anything like MADV_DONTNEED.
>> -void ReleaseMemoryPagesToOS(uptr beg, uptr end) {}
>> +void ReleaseMemoryPagesToOS(uptr beg, uptr end) {
>> + uptr beg_aligned = RoundUpTo(beg, GetPageSize());
>> + uptr end_aligned = RoundDownTo(end, GetPageSize());
>> + if (beg_aligned < end_aligned) {
>> + zx_handle_t root_vmar = _zx_vmar_root_self();
>> + CHECK_NE(root_vmar, ZX_HANDLE_INVALID);
>> + zx_status_t status =
>> + _zx_vmar_op_range(root_vmar, ZX_VMAR_OP_DECOMMIT, beg_aligned,
>> + end_aligned - beg_aligned, nullptr, 0);
>> + CHECK_EQ(status, ZX_OK);
>> + }
>> +}
>>
>> void DumpProcessMap() {
>> // TODO(mcgrathr): write it
>> @@ -412,8 +418,9 @@ bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size,
>> uint64_t vmo_size;
>> status = _zx_vmo_get_size(vmo, &vmo_size);
>> if (status == ZX_OK) {
>> - if (vmo_size < max_len) max_len = vmo_size;
>> - size_t map_size = RoundUpTo(max_len, PAGE_SIZE);
>> + if (vmo_size < max_len)
>> + max_len = vmo_size;
>> + size_t map_size = RoundUpTo(max_len, GetPageSize());
>> uintptr_t addr;
>> status = _zx_vmar_map(_zx_vmar_root_self(), ZX_VM_PERM_READ, 0, vmo, 0,
>> map_size, &addr);
>> @@ -425,7 +432,8 @@ bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size,
>> }
>> _zx_handle_close(vmo);
>> }
>> - if (status != ZX_OK && errno_p) *errno_p = status;
>> + if (status != ZX_OK && errno_p)
>> + *errno_p = status;
>> return status == ZX_OK;
>> }
>>
>> @@ -499,9 +507,7 @@ bool GetRandom(void *buffer, uptr length, bool blocking) {
>> return true;
>> }
>>
>> -u32 GetNumberOfCPUs() {
>> - return zx_system_get_num_cpus();
>> -}
>> +u32 GetNumberOfCPUs() { return zx_system_get_num_cpus(); }
>>
>> uptr GetRSS() { UNIMPLEMENTED(); }
>>
>> @@ -529,6 +535,10 @@ void __sanitizer_set_report_path(const char *path) {
>> void __sanitizer_set_report_fd(void *fd) {
>> UNREACHABLE("not available on Fuchsia");
>> }
>> +
>> +const char *__sanitizer_get_report_path() {
>> + UNREACHABLE("not available on Fuchsia");
>> +}
>> } // extern "C"
>>
>> #endif // SANITIZER_FUCHSIA
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_interface_internal.h b/libsanitizer/sanitizer_common/sanitizer_interface_internal.h
>> index be8023e9e16..0b001c1c483 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_interface_internal.h
>> +++ b/libsanitizer/sanitizer_common/sanitizer_interface_internal.h
>> @@ -28,6 +28,10 @@ extern "C" {
>> // (casted to void *).
>> SANITIZER_INTERFACE_ATTRIBUTE
>> void __sanitizer_set_report_fd(void *fd);
>> + // Get the current full report file path, if a path was specified by
>> + // an earlier call to __sanitizer_set_report_path. Returns null otherwise.
>> + SANITIZER_INTERFACE_ATTRIBUTE
>> + const char *__sanitizer_get_report_path();
>>
>> typedef struct {
>> int coverage_sandboxed;
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_internal_defs.h b/libsanitizer/sanitizer_common/sanitizer_internal_defs.h
>> index d8f0540037d..84053fec264 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_internal_defs.h
>> +++ b/libsanitizer/sanitizer_common/sanitizer_internal_defs.h
>> @@ -409,6 +409,9 @@ inline void Trap() {
>> (void)enable_fp; \
>> } while (0)
>>
>> +constexpr u32 kInvalidTid = -1;
>> +constexpr u32 kMainTid = 0;
>> +
>> } // namespace __sanitizer
>>
>> namespace __asan {
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_libignore.cpp b/libsanitizer/sanitizer_common/sanitizer_libignore.cpp
>> index 9ea19bc21fa..a65d3d896e3 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_libignore.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_libignore.cpp
>> @@ -38,7 +38,7 @@ void LibIgnore::AddIgnoredLibrary(const char *name_templ) {
>> void LibIgnore::OnLibraryLoaded(const char *name) {
>> BlockingMutexLock lock(&mutex_);
>> // Try to match suppressions with symlink target.
>> - InternalScopedString buf(kMaxPathLength);
>> + InternalMmapVector<char> buf(kMaxPathLength);
>> if (name && internal_readlink(name, buf.data(), buf.size() - 1) > 0 &&
>> buf[0]) {
>> for (uptr i = 0; i < count_; i++) {
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_linux.cpp b/libsanitizer/sanitizer_common/sanitizer_linux.cpp
>> index 379f6d9e294..b371477755f 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_linux.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_linux.cpp
>> @@ -183,6 +183,14 @@ uptr internal_munmap(void *addr, uptr length) {
>> return internal_syscall(SYSCALL(munmap), (uptr)addr, length);
>> }
>>
>> +#if SANITIZER_LINUX
>> +uptr internal_mremap(void *old_address, uptr old_size, uptr new_size, int flags,
>> + void *new_address) {
>> + return internal_syscall(SYSCALL(mremap), (uptr)old_address, old_size,
>> + new_size, flags, (uptr)new_address);
>> +}
>> +#endif
>> +
>> int internal_mprotect(void *addr, uptr length, int prot) {
>> return internal_syscall(SYSCALL(mprotect), (uptr)addr, length, prot);
>> }
>> @@ -489,22 +497,24 @@ int TgKill(pid_t pid, tid_t tid, int sig) {
>> }
>> #endif
>>
>> -#if !SANITIZER_SOLARIS && !SANITIZER_NETBSD
>> +#if SANITIZER_GLIBC
>> u64 NanoTime() {
>> -#if SANITIZER_FREEBSD
>> - timeval tv;
>> -#else
>> kernel_timeval tv;
>> -#endif
>> internal_memset(&tv, 0, sizeof(tv));
>> internal_syscall(SYSCALL(gettimeofday), &tv, 0);
>> - return (u64)tv.tv_sec * 1000*1000*1000 + tv.tv_usec * 1000;
>> + return (u64)tv.tv_sec * 1000 * 1000 * 1000 + tv.tv_usec * 1000;
>> }
>> -
>> +// Used by real_clock_gettime.
>> uptr internal_clock_gettime(__sanitizer_clockid_t clk_id, void *tp) {
>> return internal_syscall(SYSCALL(clock_gettime), clk_id, tp);
>> }
>> -#endif // !SANITIZER_SOLARIS && !SANITIZER_NETBSD
>> +#elif !SANITIZER_SOLARIS && !SANITIZER_NETBSD
>> +u64 NanoTime() {
>> + struct timespec ts;
>> + clock_gettime(CLOCK_REALTIME, &ts);
>> + return (u64)ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
>> +}
>> +#endif
>>
>> // Like getenv, but reads env directly from /proc (on Linux) or parses the
>> // 'environ' array (on some others) and does not use libc. This function
>> @@ -1334,50 +1344,42 @@ uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
>> #elif SANITIZER_RISCV64
>> uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
>> int *parent_tidptr, void *newtls, int *child_tidptr) {
>> - long long res;
>> if (!fn || !child_stack)
>> return -EINVAL;
>> +
>> CHECK_EQ(0, (uptr)child_stack % 16);
>> - 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 int (*__fn)(void *) __asm__("a0") = fn;
>> + register int res __asm__("a0");
>> + register int __flags __asm__("a0") = flags;
>> register void *__stack __asm__("a1") = child_stack;
>> - register int __flags __asm__("a2") = flags;
>> - register void *__arg __asm__("a3") = arg;
>> - register int *__ptid __asm__("a4") = parent_tidptr;
>> - register void *__tls __asm__("a5") = newtls;
>> - register int *__ctid __asm__("a6") = child_tidptr;
>> + register int *__ptid __asm__("a2") = parent_tidptr;
>> + register void *__tls __asm__("a3") = newtls;
>> + register int *__ctid __asm__("a4") = child_tidptr;
>> + register int (*__fn)(void *) __asm__("a5") = fn;
>> + register void *__arg __asm__("a6") = arg;
>> + register int nr_clone __asm__("a7") = __NR_clone;
>>
>> __asm__ __volatile__(
>> - "mv a0,a2\n" /* flags */
>> - "mv a2,a4\n" /* ptid */
>> - "mv a3,a5\n" /* tls */
>> - "mv a4,a6\n" /* ctid */
>> - "addi a7, zero, %9\n" /* clone */
>> -
>> "ecall\n"
>>
>> - /* if (%r0 != 0)
>> - * return %r0;
>> + /* if (a0 != 0)
>> + * return a0;
>> */
>> "bnez a0, 1f\n"
>>
>> - /* In the child, now. Call "fn(arg)". */
>> - "ld a0, 8(sp)\n"
>> - "ld a1, 16(sp)\n"
>> - "jalr a1\n"
>> + // In the child, now. Call "fn(arg)".
>> + "mv a0, a6\n"
>> + "jalr a5\n"
>>
>> - /* Call _exit(%r0). */
>> - "addi a7, zero, %10\n"
>> + // Call _exit(a0).
>> + "addi a7, zero, %9\n"
>> "ecall\n"
>> "1:\n"
>>
>> : "=r"(res)
>> - : "i"(-EINVAL), "r"(__fn), "r"(__stack), "r"(__flags), "r"(__arg),
>> - "r"(__ptid), "r"(__tls), "r"(__ctid), "i"(__NR_clone), "i"(__NR_exit)
>> - : "ra", "memory");
>> + : "0"(__flags), "r"(__stack), "r"(__ptid), "r"(__tls), "r"(__ctid),
>> + "r"(__fn), "r"(__arg), "r"(nr_clone), "i"(__NR_exit)
>> + : "memory");
>> return res;
>> }
>> #elif defined(__aarch64__)
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_linux.h b/libsanitizer/sanitizer_common/sanitizer_linux.h
>> index 24902d1b6bc..9a23fcfb3b9 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_linux.h
>> +++ b/libsanitizer/sanitizer_common/sanitizer_linux.h
>> @@ -49,7 +49,9 @@ uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count);
>> uptr internal_sigaltstack(const void* ss, void* oss);
>> uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set,
>> __sanitizer_sigset_t *oldset);
>> +#if SANITIZER_GLIBC
>> uptr internal_clock_gettime(__sanitizer_clockid_t clk_id, void *tp);
>> +#endif
>>
>> // Linux-only syscalls.
>> #if SANITIZER_LINUX
>> @@ -96,7 +98,6 @@ class ThreadLister {
>> // Exposed for testing.
>> uptr ThreadDescriptorSize();
>> uptr ThreadSelf();
>> -uptr ThreadSelfOffset();
>>
>> // Matches a library's file name against a base name (stripping path and version
>> // information).
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp
>> index bc10e89b1ed..572aa86fa53 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp
>> @@ -36,6 +36,7 @@
>> #include <link.h>
>> #include <pthread.h>
>> #include <signal.h>
>> +#include <sys/mman.h>
>> #include <sys/resource.h>
>> #include <syslog.h>
>>
>> @@ -48,6 +49,10 @@
>> #include <osreldate.h>
>> #include <sys/sysctl.h>
>> #define pthread_getattr_np pthread_attr_get_np
>> +// The MAP_NORESERVE define has been removed in FreeBSD 11.x, and even before
>> +// that, it was never implemented. So just define it to zero.
>> +#undef MAP_NORESERVE
>> +#define MAP_NORESERVE 0
>> #endif
>>
>> #if SANITIZER_NETBSD
>> @@ -183,85 +188,35 @@ __attribute__((unused)) static bool GetLibcVersion(int *major, int *minor,
>> #endif
>> }
>>
>> -#if !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_GO && \
>> - !SANITIZER_NETBSD && !SANITIZER_SOLARIS
>> -static uptr g_tls_size;
>> +// True if we can use dlpi_tls_data. glibc before 2.25 may leave NULL (BZ
>> +// #19826) so dlpi_tls_data cannot be used.
>> +//
>> +// musl before 1.2.3 and FreeBSD as of 12.2 incorrectly set dlpi_tls_data to
>> +// the TLS initialization image
>> +// https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=254774
>> +__attribute__((unused)) static int g_use_dlpi_tls_data;
>>
>> -#ifdef __i386__
>> -#define CHECK_GET_TLS_STATIC_INFO_VERSION (!__GLIBC_PREREQ(2, 27))
>> -#else
>> -#define CHECK_GET_TLS_STATIC_INFO_VERSION 0
>> -#endif
>> +#if SANITIZER_GLIBC && !SANITIZER_GO
>> +__attribute__((unused)) static uptr g_tls_size;
>> +void InitTlsSize() {
>> + int major, minor, patch;
>> + g_use_dlpi_tls_data =
>> + GetLibcVersion(&major, &minor, &patch) && major == 2 && minor >= 25;
>>
>> -#if CHECK_GET_TLS_STATIC_INFO_VERSION
>> -#define DL_INTERNAL_FUNCTION __attribute__((regparm(3), stdcall))
>> -#else
>> -#define DL_INTERNAL_FUNCTION
>> +#if defined(__x86_64__) || defined(__powerpc64__)
>> + void *get_tls_static_info = dlsym(RTLD_NEXT, "_dl_get_tls_static_info");
>> + size_t tls_align;
>> + ((void (*)(size_t *, size_t *))get_tls_static_info)(&g_tls_size, &tls_align);
>> #endif
>> -
>> -namespace {
>> -struct GetTlsStaticInfoCall {
>> - typedef void (*get_tls_func)(size_t*, size_t*);
>> -};
>> -struct GetTlsStaticInfoRegparmCall {
>> - typedef void (*get_tls_func)(size_t*, size_t*) DL_INTERNAL_FUNCTION;
>> -};
>> -
>> -template <typename T>
>> -void CallGetTls(void* ptr, size_t* size, size_t* align) {
>> - typename T::get_tls_func get_tls;
>> - CHECK_EQ(sizeof(get_tls), sizeof(ptr));
>> - internal_memcpy(&get_tls, &ptr, sizeof(ptr));
>> - CHECK_NE(get_tls, 0);
>> - get_tls(size, align);
>> -}
>> -
>> -bool CmpLibcVersion(int major, int minor, int patch) {
>> - int ma;
>> - int mi;
>> - int pa;
>> - if (!GetLibcVersion(&ma, &mi, &pa))
>> - return false;
>> - if (ma > major)
>> - return true;
>> - if (ma < major)
>> - return false;
>> - if (mi > minor)
>> - return true;
>> - if (mi < minor)
>> - return false;
>> - return pa >= patch;
>> -}
>> -
>> -} // namespace
>> -
>> -void InitTlsSize() {
>> - // all current supported platforms have 16 bytes stack alignment
>> - const size_t kStackAlign = 16;
>> - void *get_tls_static_info_ptr = dlsym(RTLD_NEXT, "_dl_get_tls_static_info");
>> - size_t tls_size = 0;
>> - size_t tls_align = 0;
>> - // On i?86, _dl_get_tls_static_info used to be internal_function, i.e.
>> - // __attribute__((regparm(3), stdcall)) before glibc 2.27 and is normal
>> - // function in 2.27 and later.
>> - if (CHECK_GET_TLS_STATIC_INFO_VERSION && !CmpLibcVersion(2, 27, 0))
>> - CallGetTls<GetTlsStaticInfoRegparmCall>(get_tls_static_info_ptr,
>> - &tls_size, &tls_align);
>> - else
>> - CallGetTls<GetTlsStaticInfoCall>(get_tls_static_info_ptr,
>> - &tls_size, &tls_align);
>> - if (tls_align < kStackAlign)
>> - tls_align = kStackAlign;
>> - g_tls_size = RoundUpTo(tls_size, tls_align);
>> }
>> #else
>> void InitTlsSize() { }
>> -#endif
>> +#endif // SANITIZER_GLIBC && !SANITIZER_GO
>>
>> -#if (defined(__x86_64__) || defined(__i386__) || defined(__mips__) || \
>> - defined(__aarch64__) || defined(__powerpc64__) || defined(__s390__) || \
>> - defined(__arm__) || SANITIZER_RISCV64) && \
>> - SANITIZER_LINUX && !SANITIZER_ANDROID
>> +// On glibc x86_64, ThreadDescriptorSize() needs to be precise due to the usage
>> +// of g_tls_size. On other targets, ThreadDescriptorSize() is only used by lsan
>> +// to get the pointer to thread-specific data keys in the thread control block.
>> +#if (SANITIZER_FREEBSD || SANITIZER_LINUX) && !SANITIZER_ANDROID
>> // sizeof(struct pthread) from glibc.
>> static atomic_uintptr_t thread_descriptor_size;
>>
>> @@ -294,9 +249,18 @@ uptr ThreadDescriptorSize() {
>> val = FIRST_32_SECOND_64(1168, 2288);
>> else if (minor <= 14)
>> val = FIRST_32_SECOND_64(1168, 2304);
>> - else
>> + else if (minor < 32) // Unknown version
>> val = FIRST_32_SECOND_64(1216, 2304);
>> + else // minor == 32
>> + val = FIRST_32_SECOND_64(1344, 2496);
>> }
>> +#elif defined(__s390__) || defined(__sparc__)
>> + // The size of a prefix of TCB including pthread::{specific_1stblock,specific}
>> + // suffices. Just return offsetof(struct pthread, specific_used), which hasn't
>> + // changed since 2007-05. Technically this applies to i386/x86_64 as well but
>> + // we call _dl_get_tls_static_info and need the precise size of struct
>> + // pthread.
>> + return FIRST_32_SECOND_64(524, 1552);
>> #elif defined(__mips__)
>> // TODO(sagarthakur): add more values as per different glibc versions.
>> val = FIRST_32_SECOND_64(1152, 1776);
>> @@ -320,21 +284,12 @@ uptr ThreadDescriptorSize() {
>> val = 1776;
>> #elif defined(__powerpc64__)
>> val = 1776; // from glibc.ppc64le 2.20-8.fc21
>> -#elif defined(__s390__)
>> - val = FIRST_32_SECOND_64(1152, 1776); // valid for glibc 2.22
>> #endif
>> if (val)
>> atomic_store_relaxed(&thread_descriptor_size, val);
>> return val;
>> }
>>
>> -// The offset at which pointer to self is located in the thread descriptor.
>> -const uptr kThreadSelfOffset = FIRST_32_SECOND_64(8, 16);
>> -
>> -uptr ThreadSelfOffset() {
>> - return kThreadSelfOffset;
>> -}
>> -
>> #if defined(__mips__) || defined(__powerpc64__) || SANITIZER_RISCV64
>> // TlsPreTcbSize includes size of struct pthread_descr and size of tcb
>> // head structure. It lies before the static tls blocks.
>> @@ -353,68 +308,74 @@ static uptr TlsPreTcbSize() {
>> }
>> #endif
>>
>> -uptr ThreadSelf() {
>> - uptr descr_addr;
>> -#if defined(__i386__)
>> - asm("mov %%gs:%c1,%0" : "=r"(descr_addr) : "i"(kThreadSelfOffset));
>> -#elif defined(__x86_64__)
>> - asm("mov %%fs:%c1,%0" : "=r"(descr_addr) : "i"(kThreadSelfOffset));
>> -#elif defined(__mips__)
>> - // MIPS uses TLS variant I. The thread pointer (in hardware register $29)
>> - // points to the end of the TCB + 0x7000. The pthread_descr structure is
>> - // immediately in front of the TCB. TlsPreTcbSize() includes the size of the
>> - // TCB and the size of pthread_descr.
>> - const uptr kTlsTcbOffset = 0x7000;
>> - uptr thread_pointer;
>> - asm volatile(".set push;\
>> - .set mips64r2;\
>> - rdhwr %0,$29;\
>> - .set pop" : "=r" (thread_pointer));
>> - descr_addr = thread_pointer - kTlsTcbOffset - TlsPreTcbSize();
>> -#elif defined(__aarch64__) || defined(__arm__)
>> - descr_addr = reinterpret_cast<uptr>(__builtin_thread_pointer()) -
>> - ThreadDescriptorSize();
>> -#elif SANITIZER_RISCV64
>> - // https://github.com/riscv/riscv-elf-psabi-doc/issues/53
>> - uptr thread_pointer = reinterpret_cast<uptr>(__builtin_thread_pointer());
>> - descr_addr = thread_pointer - TlsPreTcbSize();
>> -#elif defined(__s390__)
>> - descr_addr = reinterpret_cast<uptr>(__builtin_thread_pointer());
>> -#elif defined(__powerpc64__)
>> - // PPC64LE uses TLS variant I. The thread pointer (in GPR 13)
>> - // points to the end of the TCB + 0x7000. The pthread_descr structure is
>> - // immediately in front of the TCB. TlsPreTcbSize() includes the size of the
>> - // TCB and the size of pthread_descr.
>> - const uptr kTlsTcbOffset = 0x7000;
>> - uptr thread_pointer;
>> - asm("addi %0,13,%1" : "=r"(thread_pointer) : "I"(-kTlsTcbOffset));
>> - descr_addr = thread_pointer - TlsPreTcbSize();
>> -#else
>> -#error "unsupported CPU arch"
>> -#endif
>> - return descr_addr;
>> -}
>> -#endif // (x86_64 || i386 || MIPS) && SANITIZER_LINUX
>> +#if !SANITIZER_GO
>> +namespace {
>> +struct TlsBlock {
>> + uptr begin, end, align;
>> + size_t tls_modid;
>> + bool operator<(const TlsBlock &rhs) const { return begin < rhs.begin; }
>> +};
>> +} // namespace
>>
>> -#if SANITIZER_FREEBSD
>> -static void **ThreadSelfSegbase() {
>> - void **segbase = 0;
>> -#if defined(__i386__)
>> - // sysarch(I386_GET_GSBASE, segbase);
>> - __asm __volatile("mov %%gs:0, %0" : "=r" (segbase));
>> -#elif defined(__x86_64__)
>> - // sysarch(AMD64_GET_FSBASE, segbase);
>> - __asm __volatile("movq %%fs:0, %0" : "=r" (segbase));
>> -#else
>> -#error "unsupported CPU arch"
>> +extern "C" void *__tls_get_addr(size_t *);
>> +
>> +static int CollectStaticTlsBlocks(struct dl_phdr_info *info, size_t size,
>> + void *data) {
>> + if (!info->dlpi_tls_modid)
>> + return 0;
>> + uptr begin = (uptr)info->dlpi_tls_data;
>> +#ifndef __s390__
>> + if (!g_use_dlpi_tls_data) {
>> + // Call __tls_get_addr as a fallback. This forces TLS allocation on glibc
>> + // and FreeBSD.
>> + size_t mod_and_off[2] = {info->dlpi_tls_modid, 0};
>> + begin = (uptr)__tls_get_addr(mod_and_off);
>> + }
>> #endif
>> - return segbase;
>> + for (unsigned i = 0; i != info->dlpi_phnum; ++i)
>> + if (info->dlpi_phdr[i].p_type == PT_TLS) {
>> + static_cast<InternalMmapVector<TlsBlock> *>(data)->push_back(
>> + TlsBlock{begin, begin + info->dlpi_phdr[i].p_memsz,
>> + info->dlpi_phdr[i].p_align, info->dlpi_tls_modid});
>> + break;
>> + }
>> + return 0;
>> }
>>
>> -uptr ThreadSelf() {
>> - return (uptr)ThreadSelfSegbase()[2];
>> -}
>> -#endif // SANITIZER_FREEBSD
>> +__attribute__((unused)) static void GetStaticTlsBoundary(uptr *addr, uptr *size,
>> + uptr *align) {
>> + InternalMmapVector<TlsBlock> ranges;
>> + dl_iterate_phdr(CollectStaticTlsBlocks, &ranges);
>> + uptr len = ranges.size();
>> + Sort(ranges.begin(), len);
>> + // Find the range with tls_modid=1. For glibc, because libc.so uses PT_TLS,
>> + // this module is guaranteed to exist and is one of the initially loaded
>> + // modules.
>> + uptr one = 0;
>> + while (one != len && ranges[one].tls_modid != 1) ++one;
>> + if (one == len) {
>> + // This may happen with musl if no module uses PT_TLS.
>> + *addr = 0;
>> + *size = 0;
>> + *align = 1;
>> + return;
>> + }
>> + // Find the maximum consecutive ranges. We consider two modules consecutive if
>> + // the gap is smaller than the alignment. The dynamic loader places static TLS
>> + // blocks this way not to waste space.
>> + uptr l = one;
>> + *align = ranges[l].align;
>> + while (l != 0 && ranges[l].begin < ranges[l - 1].end + ranges[l - 1].align)
>> + *align = Max(*align, ranges[--l].align);
>> + uptr r = one + 1;
>> + while (r != len && ranges[r].begin < ranges[r - 1].end + ranges[r - 1].align)
>> + *align = Max(*align, ranges[r++].align);
>> + *addr = ranges[l].begin;
>> + *size = ranges[r - 1].end - ranges[l].begin;
>> +}
>> +#endif // !SANITIZER_GO
>> +#endif // (x86_64 || i386 || mips || ...) && (SANITIZER_FREEBSD ||
>> + // SANITIZER_LINUX) && !SANITIZER_ANDROID
>>
>> #if SANITIZER_NETBSD
>> static struct tls_tcb * ThreadSelfTlsTcb() {
>> @@ -465,33 +426,67 @@ static void GetTls(uptr *addr, uptr *size) {
>> *addr = 0;
>> *size = 0;
>> }
>> -#elif SANITIZER_LINUX
>> -#if defined(__x86_64__) || defined(__i386__) || defined(__s390__)
>> - *addr = ThreadSelf();
>> - *size = GetTlsSize();
>> +#elif SANITIZER_GLIBC && defined(__x86_64__)
>> + // For x86-64, use an O(1) approach which requires precise
>> + // ThreadDescriptorSize. g_tls_size was initialized in InitTlsSize.
>> + asm("mov %%fs:16,%0" : "=r"(*addr));
>> + *size = g_tls_size;
>> *addr -= *size;
>> *addr += ThreadDescriptorSize();
>> -#elif defined(__mips__) || defined(__aarch64__) || defined(__powerpc64__) || \
>> - defined(__arm__) || SANITIZER_RISCV64
>> - *addr = ThreadSelf();
>> - *size = GetTlsSize();
>> +#elif SANITIZER_GLIBC && defined(__powerpc64__)
>> + // Workaround for glibc<2.25(?). 2.27 is known to not need this.
>> + uptr tp;
>> + asm("addi %0,13,-0x7000" : "=r"(tp));
>> + const uptr pre_tcb_size = TlsPreTcbSize();
>> + *addr = tp - pre_tcb_size;
>> + *size = g_tls_size + pre_tcb_size;
>> +#elif SANITIZER_FREEBSD || SANITIZER_LINUX
>> + uptr align;
>> + GetStaticTlsBoundary(addr, size, &align);
>> +#if defined(__x86_64__) || defined(__i386__) || defined(__s390__) || \
>> + defined(__sparc__)
>> + if (SANITIZER_GLIBC) {
>> +#if defined(__x86_64__) || defined(__i386__)
>> + align = Max<uptr>(align, 64);
>> #else
>> - *addr = 0;
>> - *size = 0;
>> + align = Max<uptr>(align, 16);
>> #endif
>> -#elif SANITIZER_FREEBSD
>> - void** segbase = ThreadSelfSegbase();
>> - *addr = 0;
>> - *size = 0;
>> - if (segbase != 0) {
>> - // tcbalign = 16
>> - // tls_size = round(tls_static_space, tcbalign);
>> - // dtv = segbase[1];
>> - // dtv[2] = segbase - tls_static_space;
>> - void **dtv = (void**) segbase[1];
>> - *addr = (uptr) dtv[2];
>> - *size = (*addr == 0) ? 0 : ((uptr) segbase[0] - (uptr) dtv[2]);
>> }
>> + const uptr tp = RoundUpTo(*addr + *size, align);
>> +
>> + // lsan requires the range to additionally cover the static TLS surplus
>> + // (elf/dl-tls.c defines 1664). Otherwise there may be false positives for
>> + // allocations only referenced by tls in dynamically loaded modules.
>> + if (SANITIZER_GLIBC)
>> + *size += 1644;
>> + else if (SANITIZER_FREEBSD)
>> + *size += 128; // RTLD_STATIC_TLS_EXTRA
>> +
>> + // Extend the range to include the thread control block. On glibc, lsan needs
>> + // the range to include pthread::{specific_1stblock,specific} so that
>> + // allocations only referenced by pthread_setspecific can be scanned. This may
>> + // underestimate by at most TLS_TCB_ALIGN-1 bytes but it should be fine
>> + // because the number of bytes after pthread::specific is larger.
>> + *addr = tp - RoundUpTo(*size, align);
>> + *size = tp - *addr + ThreadDescriptorSize();
>> +#else
>> + if (SANITIZER_GLIBC)
>> + *size += 1664;
>> + else if (SANITIZER_FREEBSD)
>> + *size += 128; // RTLD_STATIC_TLS_EXTRA
>> +#if defined(__mips__) || defined(__powerpc64__) || SANITIZER_RISCV64
>> + const uptr pre_tcb_size = TlsPreTcbSize();
>> + *addr -= pre_tcb_size;
>> + *size += pre_tcb_size;
>> +#else
>> + // arm and aarch64 reserve two words at TP, so this underestimates the range.
>> + // However, this is sufficient for the purpose of finding the pointers to
>> + // thread-specific data keys.
>> + const uptr tcb_size = ThreadDescriptorSize();
>> + *addr -= tcb_size;
>> + *size += tcb_size;
>> +#endif
>> +#endif
>> #elif SANITIZER_NETBSD
>> struct tls_tcb * const tcb = ThreadSelfTlsTcb();
>> *addr = 0;
>> @@ -518,15 +513,13 @@ static void GetTls(uptr *addr, uptr *size) {
>>
>> #if !SANITIZER_GO
>> uptr GetTlsSize() {
>> -#if SANITIZER_FREEBSD || SANITIZER_ANDROID || SANITIZER_NETBSD || \
>> +#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \
>> SANITIZER_SOLARIS
>> uptr addr, size;
>> GetTls(&addr, &size);
>> return size;
>> -#elif defined(__mips__) || defined(__powerpc64__) || SANITIZER_RISCV64
>> - return RoundUpTo(g_tls_size + TlsPreTcbSize(), 16);
>> #else
>> - return g_tls_size;
>> + return 0;
>> #endif
>> }
>> #endif
>> @@ -547,10 +540,9 @@ void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
>> if (!main) {
>> // If stack and tls intersect, make them non-intersecting.
>> if (*tls_addr > *stk_addr && *tls_addr < *stk_addr + *stk_size) {
>> - CHECK_GT(*tls_addr + *tls_size, *stk_addr);
>> - CHECK_LE(*tls_addr + *tls_size, *stk_addr + *stk_size);
>> - *stk_size -= *tls_size;
>> - *tls_addr = *stk_addr + *stk_size;
>> + if (*stk_addr + *stk_size < *tls_addr + *tls_size)
>> + *tls_size = *stk_addr + *stk_size - *tls_addr;
>> + *stk_size = *tls_addr - *stk_addr;
>> }
>> }
>> #endif
>> @@ -569,20 +561,12 @@ struct DlIteratePhdrData {
>> bool first;
>> };
>>
>> -static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) {
>> - DlIteratePhdrData *data = (DlIteratePhdrData*)arg;
>> - InternalScopedString module_name(kMaxPathLength);
>> - if (data->first) {
>> - data->first = false;
>> - // First module is the binary itself.
>> - ReadBinaryNameCached(module_name.data(), module_name.size());
>> - } else if (info->dlpi_name) {
>> - module_name.append("%s", info->dlpi_name);
>> - }
>> +static int AddModuleSegments(const char *module_name, dl_phdr_info *info,
>> + InternalMmapVectorNoCtor<LoadedModule> *modules) {
>> if (module_name[0] == '\0')
>> return 0;
>> LoadedModule cur_module;
>> - cur_module.set(module_name.data(), info->dlpi_addr);
>> + cur_module.set(module_name, info->dlpi_addr);
>> for (int i = 0; i < (int)info->dlpi_phnum; i++) {
>> const Elf_Phdr *phdr = &info->dlpi_phdr[i];
>> if (phdr->p_type == PT_LOAD) {
>> @@ -594,7 +578,26 @@ static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) {
>> writable);
>> }
>> }
>> - data->modules->push_back(cur_module);
>> + modules->push_back(cur_module);
>> + return 0;
>> +}
>> +
>> +static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) {
>> + DlIteratePhdrData *data = (DlIteratePhdrData *)arg;
>> + if (data->first) {
>> + InternalMmapVector<char> module_name(kMaxPathLength);
>> + data->first = false;
>> + // First module is the binary itself.
>> + ReadBinaryNameCached(module_name.data(), module_name.size());
>> + return AddModuleSegments(module_name.data(), info, data->modules);
>> + }
>> +
>> + if (info->dlpi_name) {
>> + InternalScopedString module_name;
>> + module_name.append("%s", info->dlpi_name);
>> + return AddModuleSegments(module_name.data(), info, data->modules);
>> + }
>> +
>> return 0;
>> }
>>
>> @@ -729,13 +732,9 @@ u32 GetNumberOfCPUs() {
>> #elif SANITIZER_SOLARIS
>> return sysconf(_SC_NPROCESSORS_ONLN);
>> #else
>> -#if defined(CPU_COUNT)
>> cpu_set_t CPUs;
>> CHECK_EQ(sched_getaffinity(0, sizeof(cpu_set_t), &CPUs), 0);
>> return CPU_COUNT(&CPUs);
>> -#else
>> - return 1;
>> -#endif
>> #endif
>> }
>>
>> @@ -802,20 +801,13 @@ void LogMessageOnPrintf(const char *str) {
>>
>> #endif // SANITIZER_LINUX
>>
>> -#if SANITIZER_LINUX && !SANITIZER_GO
>> +#if SANITIZER_GLIBC && !SANITIZER_GO
>> // glibc crashes when using clock_gettime from a preinit_array function as the
>> // vDSO function pointers haven't been initialized yet. __progname is
>> // initialized after the vDSO function pointers, so if it exists, is not null
>> // and is not empty, we can use clock_gettime.
>> extern "C" SANITIZER_WEAK_ATTRIBUTE char *__progname;
>> -inline bool CanUseVDSO() {
>> - // Bionic is safe, it checks for the vDSO function pointers to be initialized.
>> - if (SANITIZER_ANDROID)
>> - return true;
>> - if (&__progname && __progname && *__progname)
>> - return true;
>> - return false;
>> -}
>> +inline bool CanUseVDSO() { return &__progname && __progname && *__progname; }
>>
>> // MonotonicNanoTime is a timing function that can leverage the vDSO by calling
>> // clock_gettime. real_clock_gettime only exists if clock_gettime is
>> @@ -835,13 +827,13 @@ u64 MonotonicNanoTime() {
>> return (u64)ts.tv_sec * (1000ULL * 1000 * 1000) + ts.tv_nsec;
>> }
>> #else
>> -// Non-Linux & Go always use the syscall.
>> +// Non-glibc & Go always use the regular function.
>> u64 MonotonicNanoTime() {
>> timespec ts;
>> - internal_clock_gettime(CLOCK_MONOTONIC, &ts);
>> + clock_gettime(CLOCK_MONOTONIC, &ts);
>> return (u64)ts.tv_sec * (1000ULL * 1000 * 1000) + ts.tv_nsec;
>> }
>> -#endif // SANITIZER_LINUX && !SANITIZER_GO
>> +#endif // SANITIZER_GLIBC && !SANITIZER_GO
>>
>> void ReExec() {
>> const char *pathname = "/proc/self/exe";
>> @@ -910,6 +902,65 @@ uptr MapDynamicShadow(uptr shadow_size_bytes, uptr shadow_scale,
>> return shadow_start;
>> }
>>
>> +static uptr MmapSharedNoReserve(uptr addr, uptr size) {
>> + return internal_mmap(
>> + reinterpret_cast<void *>(addr), size, PROT_READ | PROT_WRITE,
>> + MAP_FIXED | MAP_SHARED | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
>> +}
>> +
>> +static uptr MremapCreateAlias(uptr base_addr, uptr alias_addr,
>> + uptr alias_size) {
>> +#if SANITIZER_LINUX
>> + return internal_mremap(reinterpret_cast<void *>(base_addr), 0, alias_size,
>> + MREMAP_MAYMOVE | MREMAP_FIXED,
>> + reinterpret_cast<void *>(alias_addr));
>> +#else
>> + CHECK(false && "mremap is not supported outside of Linux");
>> + return 0;
>> +#endif
>> +}
>> +
>> +static void CreateAliases(uptr start_addr, uptr alias_size, uptr num_aliases) {
>> + uptr total_size = alias_size * num_aliases;
>> + uptr mapped = MmapSharedNoReserve(start_addr, total_size);
>> + CHECK_EQ(mapped, start_addr);
>> +
>> + for (uptr i = 1; i < num_aliases; ++i) {
>> + uptr alias_addr = start_addr + i * alias_size;
>> + CHECK_EQ(MremapCreateAlias(start_addr, alias_addr, alias_size), alias_addr);
>> + }
>> +}
>> +
>> +uptr MapDynamicShadowAndAliases(uptr shadow_size, uptr alias_size,
>> + uptr num_aliases, uptr ring_buffer_size) {
>> + CHECK_EQ(alias_size & (alias_size - 1), 0);
>> + CHECK_EQ(num_aliases & (num_aliases - 1), 0);
>> + CHECK_EQ(ring_buffer_size & (ring_buffer_size - 1), 0);
>> +
>> + const uptr granularity = GetMmapGranularity();
>> + shadow_size = RoundUpTo(shadow_size, granularity);
>> + CHECK_EQ(shadow_size & (shadow_size - 1), 0);
>> +
>> + const uptr alias_region_size = alias_size * num_aliases;
>> + const uptr alignment =
>> + 2 * Max(Max(shadow_size, alias_region_size), ring_buffer_size);
>> + const uptr left_padding = ring_buffer_size;
>> +
>> + const uptr right_size = alignment;
>> + const uptr map_size = left_padding + 2 * alignment;
>> +
>> + const uptr map_start = reinterpret_cast<uptr>(MmapNoAccess(map_size));
>> + CHECK_NE(map_start, static_cast<uptr>(-1));
>> + const uptr right_start = RoundUpTo(map_start + left_padding, alignment);
>> +
>> + UnmapFromTo(map_start, right_start - left_padding);
>> + UnmapFromTo(right_start + right_size, map_start + map_size);
>> +
>> + CreateAliases(right_start + right_size / 2, alias_size, num_aliases);
>> +
>> + return right_start;
>> +}
>> +
>> void InitializePlatformCommonFlags(CommonFlags *cf) {
>> #if SANITIZER_ANDROID
>> if (&__libc_get_static_tls_bounds == nullptr)
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_local_address_space_view.h b/libsanitizer/sanitizer_common/sanitizer_local_address_space_view.h
>> index 5d1b5264b5e..0e19c4d4a80 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_local_address_space_view.h
>> +++ b/libsanitizer/sanitizer_common/sanitizer_local_address_space_view.h
>> @@ -7,7 +7,7 @@
>> //===----------------------------------------------------------------------===//
>> //
>> // `LocalAddressSpaceView` provides the local (i.e. target and current address
>> -// space are the same) implementation of the `AddressSpaveView` interface which
>> +// space are the same) implementation of the `AddressSpaceView` interface which
>> // provides a simple interface to load memory from another process (i.e.
>> // out-of-process)
>> //
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_mac.cpp b/libsanitizer/sanitizer_common/sanitizer_mac.cpp
>> index 011ec6f4a0b..f4c6b442a14 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_mac.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_mac.cpp
>> @@ -37,13 +37,21 @@
>> extern char **environ;
>> #endif
>>
>> -#if defined(__has_include) && __has_include(<os/trace.h>) && defined(__BLOCKS__)
>> +#if defined(__has_include) && __has_include(<os/trace.h>)
>> #define SANITIZER_OS_TRACE 1
>> #include <os/trace.h>
>> #else
>> #define SANITIZER_OS_TRACE 0
>> #endif
>>
>> +// import new crash reporting api
>> +#if defined(__has_include) && __has_include(<CrashReporterClient.h>)
>> +#define HAVE_CRASHREPORTERCLIENT_H 1
>> +#include <CrashReporterClient.h>
>> +#else
>> +#define HAVE_CRASHREPORTERCLIENT_H 0
>> +#endif
>> +
>> #if !SANITIZER_IOS
>> #include <crt_externs.h> // for _NSGetArgv and _NSGetEnviron
>> #else
>> @@ -62,6 +70,7 @@ extern "C" {
>> #include <mach/mach_time.h>
>> #include <mach/vm_statistics.h>
>> #include <malloc/malloc.h>
>> +#include <os/log.h>
>> #include <pthread.h>
>> #include <sched.h>
>> #include <signal.h>
>> @@ -133,6 +142,12 @@ uptr internal_munmap(void *addr, uptr length) {
>> return munmap(addr, length);
>> }
>>
>> +uptr internal_mremap(void *old_address, uptr old_size, uptr new_size, int flags,
>> + void *new_address) {
>> + CHECK(false && "internal_mremap is unimplemented on Mac");
>> + return 0;
>> +}
>> +
>> int internal_mprotect(void *addr, uptr length, int prot) {
>> return mprotect(addr, length, prot);
>> }
>> @@ -444,7 +459,7 @@ uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {
>> // On OS X the executable path is saved to the stack by dyld. Reading it
>> // from there is much faster than calling dladdr, especially for large
>> // binaries with symbols.
>> - InternalScopedString exe_path(kMaxPathLength);
>> + InternalMmapVector<char> exe_path(kMaxPathLength);
>> uint32_t size = exe_path.size();
>> if (_NSGetExecutablePath(exe_path.data(), &size) == 0 &&
>> realpath(exe_path.data(), buf) != 0) {
>> @@ -620,6 +635,23 @@ constexpr u16 GetOSMajorKernelOffset() {
>>
>> using VersStr = char[64];
>>
>> +static uptr ApproximateOSVersionViaKernelVersion(VersStr vers) {
>> + u16 kernel_major = GetDarwinKernelVersion().major;
>> + u16 offset = GetOSMajorKernelOffset();
>> + CHECK_GE(kernel_major, offset);
>> + u16 os_major = kernel_major - offset;
>> +
>> + const char *format = "%d.0";
>> + if (TARGET_OS_OSX) {
>> + if (os_major >= 16) { // macOS 11+
>> + os_major -= 5;
>> + } else { // macOS 10.15 and below
>> + format = "10.%d";
>> + }
>> + }
>> + return internal_snprintf(vers, sizeof(VersStr), format, os_major);
>> +}
>> +
>> static void GetOSVersion(VersStr vers) {
>> uptr len = sizeof(VersStr);
>> if (SANITIZER_IOSSIM) {
>> @@ -633,17 +665,19 @@ static void GetOSVersion(VersStr vers) {
>> } else {
>> int res =
>> internal_sysctlbyname("kern.osproductversion", vers, &len, nullptr, 0);
>> - if (res) {
>> - // Fallback for XNU 17 (macOS 10.13) and below that do not provide the
>> - // `kern.osproductversion` property.
>> - u16 kernel_major = GetDarwinKernelVersion().major;
>> - u16 offset = GetOSMajorKernelOffset();
>> - CHECK_LE(kernel_major, 17);
>> - CHECK_GE(kernel_major, offset);
>> - u16 os_major = kernel_major - offset;
>> -
>> - auto format = TARGET_OS_OSX ? "10.%d" : "%d.0";
>> - len = internal_snprintf(vers, len, format, os_major);
>> +
>> + // XNU 17 (macOS 10.13) and below do not provide the sysctl
>> + // `kern.osproductversion` entry (res != 0).
>> + bool no_os_version = res != 0;
>> +
>> + // For launchd, sanitizer initialization runs before sysctl is setup
>> + // (res == 0 && len != strlen(vers), vers is not a valid version). However,
>> + // the kernel version `kern.osrelease` is available.
>> + bool launchd = (res == 0 && internal_strlen(vers) < 3);
>> + if (launchd) CHECK_EQ(internal_getpid(), 1);
>> +
>> + if (no_os_version || launchd) {
>> + len = ApproximateOSVersionViaKernelVersion(vers);
>> }
>> }
>> CHECK_LT(len, sizeof(VersStr));
>> @@ -681,7 +715,7 @@ static void MapToMacos(u16 *major, u16 *minor) {
>> }
>>
>> static MacosVersion GetMacosAlignedVersionInternal() {
>> - VersStr vers;
>> + VersStr vers = {};
>> GetOSVersion(vers);
>>
>> u16 major, minor;
>> @@ -707,7 +741,7 @@ MacosVersion GetMacosAlignedVersion() {
>> }
>>
>> DarwinKernelVersion GetDarwinKernelVersion() {
>> - VersStr vers;
>> + VersStr vers = {};
>> uptr len = sizeof(VersStr);
>> int res = internal_sysctlbyname("kern.osrelease", vers, &len, nullptr, 0);
>> CHECK_EQ(res, 0);
>> @@ -751,7 +785,51 @@ static BlockingMutex syslog_lock(LINKER_INITIALIZED);
>> void WriteOneLineToSyslog(const char *s) {
>> #if !SANITIZER_GO
>> syslog_lock.CheckLocked();
>> - asl_log(nullptr, nullptr, ASL_LEVEL_ERR, "%s", s);
>> + if (GetMacosAlignedVersion() >= MacosVersion(10, 12)) {
>> + os_log_error(OS_LOG_DEFAULT, "%{public}s", s);
>> + } else {
>> + asl_log(nullptr, nullptr, ASL_LEVEL_ERR, "%s", s);
>> + }
>> +#endif
>> +}
>> +
>> +// buffer to store crash report application information
>> +static char crashreporter_info_buff[__sanitizer::kErrorMessageBufferSize] = {};
>> +static BlockingMutex crashreporter_info_mutex(LINKER_INITIALIZED);
>> +
>> +extern "C" {
>> +// Integrate with crash reporter libraries.
>> +#if HAVE_CRASHREPORTERCLIENT_H
>> +CRASH_REPORTER_CLIENT_HIDDEN
>> +struct crashreporter_annotations_t gCRAnnotations
>> + __attribute__((section("__DATA," CRASHREPORTER_ANNOTATIONS_SECTION))) = {
>> + CRASHREPORTER_ANNOTATIONS_VERSION,
>> + 0,
>> + 0,
>> + 0,
>> + 0,
>> + 0,
>> + 0,
>> +#if CRASHREPORTER_ANNOTATIONS_VERSION > 4
>> + 0,
>> +#endif
>> +};
>> +
>> +#else
>> +// fall back to old crashreporter api
>> +static const char *__crashreporter_info__ __attribute__((__used__)) =
>> + &crashreporter_info_buff[0];
>> +asm(".desc ___crashreporter_info__, 0x10");
>> +#endif
>> +
>> +} // extern "C"
>> +
>> +static void CRAppendCrashLogMessage(const char *msg) {
>> + BlockingMutexLock l(&crashreporter_info_mutex);
>> + internal_strlcat(crashreporter_info_buff, msg,
>> + sizeof(crashreporter_info_buff));
>> +#if HAVE_CRASHREPORTERCLIENT_H
>> + (void)CRSetCrashLogMessage(crashreporter_info_buff);
>> #endif
>> }
>>
>> @@ -947,7 +1025,7 @@ void MaybeReexec() {
>> if (DyldNeedsEnvVariable() && !lib_is_in_env) {
>> // DYLD_INSERT_LIBRARIES is not set or does not contain the runtime
>> // library.
>> - InternalScopedString program_name(1024);
>> + InternalMmapVector<char> program_name(1024);
>> uint32_t buf_size = program_name.size();
>> _NSGetExecutablePath(program_name.data(), &buf_size);
>> char *new_env = const_cast<char*>(info.dli_fname);
>> @@ -1066,7 +1144,7 @@ char **GetArgv() {
>> return *_NSGetArgv();
>> }
>>
>> -#if SANITIZER_IOS
>> +#if SANITIZER_IOS && !SANITIZER_IOSSIM
>> // The task_vm_info struct is normally provided by the macOS SDK, but we need
>> // fields only available in 10.12+. Declare the struct manually to be able to
>> // build against older SDKs.
>> @@ -1106,26 +1184,35 @@ static uptr GetTaskInfoMaxAddress() {
>>
>> uptr GetMaxUserVirtualAddress() {
>> static uptr max_vm = GetTaskInfoMaxAddress();
>> - if (max_vm != 0)
>> - return max_vm - 1;
>> + if (max_vm != 0) {
>> + const uptr ret_value = max_vm - 1;
>> + CHECK_LE(ret_value, SANITIZER_MMAP_RANGE_SIZE);
>> + return ret_value;
>> + }
>>
>> // xnu cannot provide vm address limit
>> # if SANITIZER_WORDSIZE == 32
>> - return 0xffe00000 - 1;
>> + constexpr uptr fallback_max_vm = 0xffe00000 - 1;
>> # else
>> - return 0x200000000 - 1;
>> + constexpr uptr fallback_max_vm = 0x200000000 - 1;
>> # endif
>> + static_assert(fallback_max_vm <= SANITIZER_MMAP_RANGE_SIZE,
>> + "Max virtual address must be less than mmap range size.");
>> + return fallback_max_vm;
>> }
>>
>> #else // !SANITIZER_IOS
>>
>> uptr GetMaxUserVirtualAddress() {
>> # if SANITIZER_WORDSIZE == 64
>> - return (1ULL << 47) - 1; // 0x00007fffffffffffUL;
>> + constexpr uptr max_vm = (1ULL << 47) - 1; // 0x00007fffffffffffUL;
>> # else // SANITIZER_WORDSIZE == 32
>> static_assert(SANITIZER_WORDSIZE == 32, "Wrong wordsize");
>> - return (1ULL << 32) - 1; // 0xffffffff;
>> + constexpr uptr max_vm = (1ULL << 32) - 1; // 0xffffffff;
>> # endif
>> + static_assert(max_vm <= SANITIZER_MMAP_RANGE_SIZE,
>> + "Max virtual address must be less than mmap range size.");
>> + return max_vm;
>> }
>> #endif
>>
>> @@ -1180,6 +1267,12 @@ uptr MapDynamicShadow(uptr shadow_size_bytes, uptr shadow_scale,
>> return shadow_start;
>> }
>>
>> +uptr MapDynamicShadowAndAliases(uptr shadow_size, uptr alias_size,
>> + uptr num_aliases, uptr ring_buffer_size) {
>> + CHECK(false && "HWASan aliasing is unimplemented on Mac");
>> + return 0;
>> +}
>> +
>> uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding,
>> uptr *largest_gap_found,
>> uptr *max_occupied_addr) {
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_mac.h b/libsanitizer/sanitizer_common/sanitizer_mac.h
>> index a2c42b3bf4f..0b6af5a3c0e 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_mac.h
>> +++ b/libsanitizer/sanitizer_common/sanitizer_mac.h
>> @@ -14,26 +14,6 @@
>>
>> #include "sanitizer_common.h"
>> #include "sanitizer_platform.h"
>> -
>> -/* TARGET_OS_OSX is not present in SDKs before Darwin16 (macOS 10.12) use
>> - TARGET_OS_MAC (we have no support for iOS in any form for these versions,
>> - so there's no ambiguity). */
>> -#if !defined(TARGET_OS_OSX) && TARGET_OS_MAC
>> -# define TARGET_OS_OSX 1
>> -#endif
>> -
>> -/* Other TARGET_OS_xxx are not present on earlier versions, define them to
>> - 0 (we have no support for them; they are not valid targets anyway). */
>> -#ifndef TARGET_OS_IOS
>> -#define TARGET_OS_IOS 0
>> -#endif
>> -#ifndef TARGET_OS_TV
>> -#define TARGET_OS_TV 0
>> -#endif
>> -#ifndef TARGET_OS_WATCH
>> -#define TARGET_OS_WATCH 0
>> -#endif
>> -
>> #if SANITIZER_MAC
>> #include "sanitizer_posix.h"
>>
>> @@ -84,22 +64,5 @@ void RestrictMemoryToMaxAddress(uptr max_address);
>>
>> } // namespace __sanitizer
>>
>> -extern "C" {
>> -static char __crashreporter_info_buff__[__sanitizer::kErrorMessageBufferSize] =
>> - {};
>> -static const char *__crashreporter_info__ __attribute__((__used__)) =
>> - &__crashreporter_info_buff__[0];
>> -asm(".desc ___crashreporter_info__, 0x10");
>> -} // extern "C"
>> -
>> -namespace __sanitizer {
>> -static BlockingMutex crashreporter_info_mutex(LINKER_INITIALIZED);
>> -
>> -inline void CRAppendCrashLogMessage(const char *msg) {
>> - BlockingMutexLock l(&crashreporter_info_mutex);
>> - internal_strlcat(__crashreporter_info_buff__, msg,
>> - sizeof(__crashreporter_info_buff__)); }
>> -} // namespace __sanitizer
>> -
>> #endif // SANITIZER_MAC
>> #endif // SANITIZER_MAC_H
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_malloc_mac.inc b/libsanitizer/sanitizer_common/sanitizer_malloc_mac.inc
>> index 647bcdfe105..e3b664f68b6 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_malloc_mac.inc
>> +++ b/libsanitizer/sanitizer_common/sanitizer_malloc_mac.inc
>> @@ -120,11 +120,7 @@ INTERCEPTOR(int, malloc_make_nonpurgeable, void *ptr) {
>>
>> INTERCEPTOR(void, malloc_set_zone_name, malloc_zone_t *zone, const char *name) {
>> COMMON_MALLOC_ENTER();
>> - // Allocate |sizeof(COMMON_MALLOC_ZONE_NAME "-") + internal_strlen(name)|
>> - // bytes.
>> - size_t buflen =
>> - sizeof(COMMON_MALLOC_ZONE_NAME "-") + (name ? internal_strlen(name) : 0);
>> - InternalScopedString new_name(buflen);
>> + InternalScopedString new_name;
>> if (name && zone->introspect == sanitizer_zone.introspect) {
>> new_name.append(COMMON_MALLOC_ZONE_NAME "-%s", name);
>> name = new_name.data();
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_netbsd.cpp b/libsanitizer/sanitizer_common/sanitizer_netbsd.cpp
>> index 98ac7365da0..ac20f915fef 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_netbsd.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_netbsd.cpp
>> @@ -105,6 +105,12 @@ uptr internal_munmap(void *addr, uptr length) {
>> return _REAL(munmap, addr, length);
>> }
>>
>> +uptr internal_mremap(void *old_address, uptr old_size, uptr new_size, int flags,
>> + void *new_address) {
>> + CHECK(false && "internal_mremap is unimplemented on NetBSD");
>> + return 0;
>> +}
>> +
>> int internal_mprotect(void *addr, uptr length, int prot) {
>> DEFINE__REAL(int, mprotect, void *a, uptr b, int c);
>> return _REAL(mprotect, addr, length, prot);
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_platform.h b/libsanitizer/sanitizer_common/sanitizer_platform.h
>> index b2372a025c0..2f6458431c8 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_platform.h
>> +++ b/libsanitizer/sanitizer_common/sanitizer_platform.h
>> @@ -19,12 +19,25 @@
>> # error "This operating system is not supported"
>> #endif
>>
>> +// Get __GLIBC__ on a glibc platform. Exclude Android: features.h includes C
>> +// function declarations into a .S file which doesn't compile.
>> +// https://crbug.com/1162741
>> +#if __has_include(<features.h>) && !defined(__ANDROID__)
>> +#include <features.h>
>> +#endif
>> +
>> #if defined(__linux__)
>> # define SANITIZER_LINUX 1
>> #else
>> # define SANITIZER_LINUX 0
>> #endif
>>
>> +#if defined(__GLIBC__)
>> +# define SANITIZER_GLIBC 1
>> +#else
>> +# define SANITIZER_GLIBC 0
>> +#endif
>> +
>> #if defined(__FreeBSD__)
>> # define SANITIZER_FREEBSD 1
>> #else
>> @@ -46,6 +59,11 @@
>> #if defined(__APPLE__)
>> # define SANITIZER_MAC 1
>> # include <TargetConditionals.h>
>> +# if TARGET_OS_OSX
>> +# define SANITIZER_OSX 1
>> +# else
>> +# define SANITIZER_OSX 0
>> +# endif
>> # if TARGET_OS_IPHONE
>> # define SANITIZER_IOS 1
>> # else
>> @@ -60,6 +78,7 @@
>> # define SANITIZER_MAC 0
>> # define SANITIZER_IOS 0
>> # define SANITIZER_IOSSIM 0
>> +# define SANITIZER_OSX 0
>> #endif
>>
>> #if defined(__APPLE__) && TARGET_OS_IPHONE && TARGET_OS_WATCH
>> @@ -247,8 +266,12 @@
>> #define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 38)
>> #elif defined(__aarch64__)
>> # if SANITIZER_MAC
>> -// Darwin iOS/ARM64 has a 36-bit VMA, 64GiB VM
>> -# define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 36)
>> +# if SANITIZER_OSX || SANITIZER_IOSSIM
>> +# define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 47)
>> +# else
>> + // Darwin iOS/ARM64 has a 36-bit VMA, 64GiB VM
>> +# define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 36)
>> +# endif
>> # else
>> # define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 48)
>> # endif
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h b/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h
>> index 18bab346ce6..731df710df5 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h
>> +++ b/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h
>> @@ -46,6 +46,12 @@
>> #define SI_LINUX_NOT_ANDROID 0
>> #endif
>>
>> +#if SANITIZER_GLIBC
>> +#define SI_GLIBC 1
>> +#else
>> +#define SI_GLIBC 0
>> +#endif
>> +
>> #if SANITIZER_ANDROID
>> #define SI_ANDROID 1
>> #else
>> @@ -159,7 +165,7 @@
>> SANITIZER_INTERCEPT_MEMCMP && \
>> ((SI_POSIX && _GNU_SOURCE) || SI_NETBSD || SI_FREEBSD)
>> #define SANITIZER_INTERCEPT_STRNDUP SI_POSIX
>> -#define SANITIZER_INTERCEPT___STRNDUP SI_LINUX_NOT_FREEBSD
>> +#define SANITIZER_INTERCEPT___STRNDUP SI_GLIBC
>> #if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \
>> __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070
>> #define SI_MAC_DEPLOYMENT_BELOW_10_7 1
>> @@ -183,8 +189,8 @@
>> #define SANITIZER_INTERCEPT_FPUTS SI_POSIX
>> #define SANITIZER_INTERCEPT_PUTS SI_POSIX
>>
>> -#define SANITIZER_INTERCEPT_PREAD64 SI_LINUX_NOT_ANDROID || SI_SOLARIS32
>> -#define SANITIZER_INTERCEPT_PWRITE64 SI_LINUX_NOT_ANDROID || SI_SOLARIS32
>> +#define SANITIZER_INTERCEPT_PREAD64 (SI_GLIBC || SI_SOLARIS32)
>> +#define SANITIZER_INTERCEPT_PWRITE64 (SI_GLIBC || SI_SOLARIS32)
>>
>> #define SANITIZER_INTERCEPT_READV SI_POSIX
>> #define SANITIZER_INTERCEPT_WRITEV SI_POSIX
>> @@ -192,8 +198,8 @@
>> #define SANITIZER_INTERCEPT_PREADV \
>> (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID)
>> #define SANITIZER_INTERCEPT_PWRITEV SI_LINUX_NOT_ANDROID
>> -#define SANITIZER_INTERCEPT_PREADV64 SI_LINUX_NOT_ANDROID
>> -#define SANITIZER_INTERCEPT_PWRITEV64 SI_LINUX_NOT_ANDROID
>> +#define SANITIZER_INTERCEPT_PREADV64 SI_GLIBC
>> +#define SANITIZER_INTERCEPT_PWRITEV64 SI_GLIBC
>>
>> #define SANITIZER_INTERCEPT_PRCTL SI_LINUX
>>
>> @@ -201,16 +207,16 @@
>> #define SANITIZER_INTERCEPT_STRPTIME SI_POSIX
>>
>> #define SANITIZER_INTERCEPT_SCANF SI_POSIX
>> -#define SANITIZER_INTERCEPT_ISOC99_SCANF SI_LINUX_NOT_ANDROID
>> +#define SANITIZER_INTERCEPT_ISOC99_SCANF SI_GLIBC
>>
>> #ifndef SANITIZER_INTERCEPT_PRINTF
>> #define SANITIZER_INTERCEPT_PRINTF SI_POSIX
>> #define SANITIZER_INTERCEPT_PRINTF_L (SI_FREEBSD || SI_NETBSD)
>> -#define SANITIZER_INTERCEPT_ISOC99_PRINTF SI_LINUX_NOT_ANDROID
>> +#define SANITIZER_INTERCEPT_ISOC99_PRINTF SI_GLIBC
>> #endif
>>
>> #define SANITIZER_INTERCEPT___PRINTF_CHK \
>> - (SANITIZER_INTERCEPT_PRINTF && SI_LINUX_NOT_ANDROID)
>> + (SANITIZER_INTERCEPT_PRINTF && SI_GLIBC)
>>
>> #define SANITIZER_INTERCEPT_FREXP SI_NOT_FUCHSIA
>> #define SANITIZER_INTERCEPT_FREXPF_FREXPL SI_POSIX
>> @@ -220,13 +226,11 @@
>> (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
>> #define SANITIZER_INTERCEPT_GETPWENT \
>> (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
>> -#define SANITIZER_INTERCEPT_FGETGRENT_R \
>> - (SI_FREEBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
>> +#define SANITIZER_INTERCEPT_FGETGRENT_R (SI_GLIBC || SI_SOLARIS)
>> #define SANITIZER_INTERCEPT_FGETPWENT SI_LINUX_NOT_ANDROID || SI_SOLARIS
>> #define SANITIZER_INTERCEPT_GETPWENT_R \
>> - (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
>> -#define SANITIZER_INTERCEPT_FGETPWENT_R \
>> - (SI_FREEBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
>> + (SI_FREEBSD || SI_NETBSD || SI_GLIBC || SI_SOLARIS)
>> +#define SANITIZER_INTERCEPT_FGETPWENT_R (SI_FREEBSD || SI_GLIBC || SI_SOLARIS)
>> #define SANITIZER_INTERCEPT_SETPWENT \
>> (SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
>> #define SANITIZER_INTERCEPT_CLOCK_GETTIME \
>> @@ -234,8 +238,8 @@
>> #define SANITIZER_INTERCEPT_CLOCK_GETCPUCLOCKID SI_LINUX
>> #define SANITIZER_INTERCEPT_GETITIMER SI_POSIX
>> #define SANITIZER_INTERCEPT_TIME SI_POSIX
>> -#define SANITIZER_INTERCEPT_GLOB SI_LINUX_NOT_ANDROID || SI_SOLARIS
>> -#define SANITIZER_INTERCEPT_GLOB64 SI_LINUX_NOT_ANDROID
>> +#define SANITIZER_INTERCEPT_GLOB (SI_GLIBC || SI_SOLARIS)
>> +#define SANITIZER_INTERCEPT_GLOB64 SI_GLIBC
>> #define SANITIZER_INTERCEPT_WAIT SI_POSIX
>> #define SANITIZER_INTERCEPT_INET SI_POSIX
>> #define SANITIZER_INTERCEPT_PTHREAD_GETSCHEDPARAM SI_POSIX
>> @@ -250,8 +254,7 @@
>> (SI_FREEBSD || SI_LINUX_NOT_ANDROID)
>> #define SANITIZER_INTERCEPT_GETHOSTBYADDR_R \
>> (SI_FREEBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
>> -#define SANITIZER_INTERCEPT_GETHOSTENT_R \
>> - (SI_FREEBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
>> +#define SANITIZER_INTERCEPT_GETHOSTENT_R (SI_FREEBSD || SI_GLIBC || SI_SOLARIS)
>> #define SANITIZER_INTERCEPT_GETSOCKOPT SI_POSIX
>> #define SANITIZER_INTERCEPT_ACCEPT SI_POSIX
>> #define SANITIZER_INTERCEPT_ACCEPT4 (SI_LINUX_NOT_ANDROID || SI_NETBSD)
>> @@ -296,8 +299,7 @@
>> (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
>> #define SANITIZER_INTERCEPT_TCGETATTR SI_LINUX_NOT_ANDROID || SI_SOLARIS
>> #define SANITIZER_INTERCEPT_REALPATH SI_POSIX
>> -#define SANITIZER_INTERCEPT_CANONICALIZE_FILE_NAME \
>> - (SI_LINUX_NOT_ANDROID || SI_SOLARIS)
>> +#define SANITIZER_INTERCEPT_CANONICALIZE_FILE_NAME (SI_GLIBC || SI_SOLARIS)
>> #define SANITIZER_INTERCEPT_CONFSTR \
>> (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
>> #define SANITIZER_INTERCEPT_SCHED_GETAFFINITY SI_LINUX_NOT_ANDROID
>> @@ -324,7 +326,7 @@
>> #define SANITIZER_INTERCEPT_SIGPROCMASK SI_POSIX
>> #define SANITIZER_INTERCEPT_PTHREAD_SIGMASK SI_POSIX
>> #define SANITIZER_INTERCEPT_BACKTRACE \
>> - (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
>> + (SI_FREEBSD || SI_NETBSD || SI_GLIBC || SI_SOLARIS)
>> #define SANITIZER_INTERCEPT_GETMNTENT SI_LINUX
>> #define SANITIZER_INTERCEPT_GETMNTENT_R SI_LINUX_NOT_ANDROID
>> #define SANITIZER_INTERCEPT_STATFS \
>> @@ -342,11 +344,11 @@
>> #define SANITIZER_INTERCEPT_SHMCTL \
>> (((SI_FREEBSD || SI_LINUX_NOT_ANDROID) && SANITIZER_WORDSIZE == 64) || \
>> SI_NETBSD || SI_SOLARIS) // NOLINT
>> -#define SANITIZER_INTERCEPT_RANDOM_R SI_LINUX_NOT_ANDROID
>> +#define SANITIZER_INTERCEPT_RANDOM_R SI_GLIBC
>> #define SANITIZER_INTERCEPT_PTHREAD_ATTR_GET SI_POSIX
>> #define SANITIZER_INTERCEPT_PTHREAD_ATTR_GETINHERITSCHED \
>> (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
>> -#define SANITIZER_INTERCEPT_PTHREAD_ATTR_GETAFFINITY_NP SI_LINUX_NOT_ANDROID
>> +#define SANITIZER_INTERCEPT_PTHREAD_ATTR_GETAFFINITY_NP SI_GLIBC
>> #define SANITIZER_INTERCEPT_PTHREAD_ATTR_GET_SCHED SI_POSIX
>> #define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPSHARED \
>> (SI_POSIX && !SI_NETBSD)
>> @@ -360,7 +362,7 @@
>> #define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETROBUST_NP SI_LINUX_NOT_ANDROID
>> #define SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GETPSHARED \
>> (SI_POSIX && !SI_NETBSD)
>> -#define SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GETKIND_NP SI_LINUX_NOT_ANDROID
>> +#define SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GETKIND_NP SI_GLIBC
>> #define SANITIZER_INTERCEPT_PTHREAD_CONDATTR_GETPSHARED (SI_POSIX && !SI_NETBSD)
>> #define SANITIZER_INTERCEPT_PTHREAD_CONDATTR_GETCLOCK \
>> (SI_LINUX_NOT_ANDROID || SI_SOLARIS)
>> @@ -368,7 +370,7 @@
>> (SI_LINUX_NOT_ANDROID && !SI_NETBSD)
>> #define SANITIZER_INTERCEPT_THR_EXIT SI_FREEBSD
>> #define SANITIZER_INTERCEPT_TMPNAM SI_POSIX
>> -#define SANITIZER_INTERCEPT_TMPNAM_R SI_LINUX_NOT_ANDROID || SI_SOLARIS
>> +#define SANITIZER_INTERCEPT_TMPNAM_R (SI_GLIBC || SI_SOLARIS)
>> #define SANITIZER_INTERCEPT_PTSNAME SI_LINUX
>> #define SANITIZER_INTERCEPT_PTSNAME_R SI_LINUX
>> #define SANITIZER_INTERCEPT_TTYNAME SI_POSIX
>> @@ -381,7 +383,7 @@
>> #define SANITIZER_INTERCEPT_LGAMMAL (SI_POSIX && !SI_NETBSD)
>> #define SANITIZER_INTERCEPT_LGAMMA_R (SI_FREEBSD || SI_LINUX || SI_SOLARIS)
>> #define SANITIZER_INTERCEPT_LGAMMAL_R SI_LINUX_NOT_ANDROID || SI_SOLARIS
>> -#define SANITIZER_INTERCEPT_DRAND48_R SI_LINUX_NOT_ANDROID
>> +#define SANITIZER_INTERCEPT_DRAND48_R SI_GLIBC
>> #define SANITIZER_INTERCEPT_RAND_R \
>> (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
>> #define SANITIZER_INTERCEPT_ICONV \
>> @@ -396,12 +398,12 @@
>> (SI_LINUX || SI_FREEBSD || SI_NETBSD || SI_MAC || SI_SOLARIS)
>>
>> #define SANITIZER_INTERCEPT_PTHREAD_MUTEX SI_POSIX
>> -#define SANITIZER_INTERCEPT___PTHREAD_MUTEX SI_LINUX_NOT_ANDROID
>> +#define SANITIZER_INTERCEPT___PTHREAD_MUTEX SI_GLIBC
>> #define SANITIZER_INTERCEPT___LIBC_MUTEX SI_NETBSD
>> #define SANITIZER_INTERCEPT_PTHREAD_SETNAME_NP \
>> - (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
>> + (SI_FREEBSD || SI_NETBSD || SI_GLIBC || SI_SOLARIS)
>> #define SANITIZER_INTERCEPT_PTHREAD_GETNAME_NP \
>> - (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
>> + (SI_FREEBSD || SI_NETBSD || SI_GLIBC || SI_SOLARIS)
>>
>> #define SANITIZER_INTERCEPT_TLS_GET_ADDR \
>> (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
>> @@ -419,19 +421,19 @@
>> #else
>> #define SANITIZER_INTERCEPT_AEABI_MEM 0
>> #endif
>> -#define SANITIZER_INTERCEPT___BZERO SI_MAC || SI_LINUX_NOT_ANDROID
>> +#define SANITIZER_INTERCEPT___BZERO SI_MAC || SI_GLIBC
>> #define SANITIZER_INTERCEPT_BZERO SI_LINUX_NOT_ANDROID
>> #define SANITIZER_INTERCEPT_FTIME (!SI_FREEBSD && !SI_NETBSD && SI_POSIX)
>> -#define SANITIZER_INTERCEPT_XDR SI_LINUX_NOT_ANDROID || SI_SOLARIS
>> -#define SANITIZER_INTERCEPT_XDRREC SI_LINUX_NOT_ANDROID
>> +#define SANITIZER_INTERCEPT_XDR (SI_GLIBC || SI_SOLARIS)
>> +#define SANITIZER_INTERCEPT_XDRREC SI_GLIBC
>> #define SANITIZER_INTERCEPT_TSEARCH \
>> (SI_LINUX_NOT_ANDROID || SI_MAC || SI_NETBSD || SI_SOLARIS)
>> -#define SANITIZER_INTERCEPT_LIBIO_INTERNALS SI_LINUX_NOT_ANDROID
>> +#define SANITIZER_INTERCEPT_LIBIO_INTERNALS SI_GLIBC
>> #define SANITIZER_INTERCEPT_FOPEN SI_POSIX
>> -#define SANITIZER_INTERCEPT_FOPEN64 SI_LINUX_NOT_ANDROID || SI_SOLARIS32
>> +#define SANITIZER_INTERCEPT_FOPEN64 (SI_GLIBC || SI_SOLARIS32)
>> #define SANITIZER_INTERCEPT_OPEN_MEMSTREAM \
>> (SI_LINUX_NOT_ANDROID || SI_NETBSD || SI_SOLARIS)
>> -#define SANITIZER_INTERCEPT_OBSTACK SI_LINUX_NOT_ANDROID
>> +#define SANITIZER_INTERCEPT_OBSTACK SI_GLIBC
>> #define SANITIZER_INTERCEPT_FFLUSH SI_POSIX
>> #define SANITIZER_INTERCEPT_FCLOSE SI_POSIX
>>
>> @@ -456,7 +458,7 @@
>> #define SANITIZER_INTERCEPT_CTERMID_R (SI_MAC || SI_FREEBSD || SI_SOLARIS)
>>
>> #define SANITIZER_INTERCEPTOR_HOOKS \
>> - (SI_LINUX || SI_MAC || SI_WINDOWS || SI_NETBSD)
>> + (SI_LINUX || SI_MAC || SI_WINDOWS || SI_FREEBSD || SI_NETBSD || SI_SOLARIS)
>> #define SANITIZER_INTERCEPT_RECV_RECVFROM SI_POSIX
>> #define SANITIZER_INTERCEPT_SEND_SENDTO SI_POSIX
>> #define SANITIZER_INTERCEPT_EVENTFD_READ_WRITE SI_LINUX
>> @@ -479,20 +481,12 @@
>>
>> #define SANITIZER_INTERCEPT_MMAP SI_POSIX
>> #define SANITIZER_INTERCEPT_MMAP64 SI_LINUX_NOT_ANDROID
>> -#define SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO \
>> - (!SI_FREEBSD && !SI_MAC && !SI_NETBSD && SI_NOT_FUCHSIA && SI_NOT_RTEMS && \
>> - !SI_SOLARIS) // NOLINT
>> +#define SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO (SI_GLIBC || SI_ANDROID)
>> #define SANITIZER_INTERCEPT_MEMALIGN \
>> (!SI_FREEBSD && !SI_MAC && !SI_NETBSD && SI_NOT_RTEMS)
>> -#define SANITIZER_INTERCEPT___LIBC_MEMALIGN \
>> - (!SI_FREEBSD && !SI_MAC && !SI_NETBSD && !SI_OPENBSD && SI_NOT_RTEMS && \
>> - !SI_ANDROID) // NOLINT
>> -#define SANITIZER_INTERCEPT_PVALLOC \
>> - (!SI_FREEBSD && !SI_MAC && !SI_NETBSD && SI_NOT_FUCHSIA && SI_NOT_RTEMS && \
>> - !SI_SOLARIS) // NOLINT
>> -#define SANITIZER_INTERCEPT_CFREE \
>> - (!SI_FREEBSD && !SI_MAC && !SI_NETBSD && SI_NOT_FUCHSIA && SI_NOT_RTEMS && \
>> - !SI_SOLARIS && !SANITIZER_ANDROID) // NOLINT
>> +#define SANITIZER_INTERCEPT___LIBC_MEMALIGN SI_GLIBC
>> +#define SANITIZER_INTERCEPT_PVALLOC (SI_GLIBC || SI_ANDROID)
>> +#define SANITIZER_INTERCEPT_CFREE (SI_GLIBC && !SANITIZER_RISCV64)
>> #define SANITIZER_INTERCEPT_REALLOCARRAY SI_POSIX
>> #define SANITIZER_INTERCEPT_ALIGNED_ALLOC (!SI_MAC && SI_NOT_RTEMS)
>> #define SANITIZER_INTERCEPT_MALLOC_USABLE_SIZE (!SI_MAC && !SI_NETBSD)
>> @@ -532,7 +526,7 @@
>> #define SANITIZER_INTERCEPT_STRMODE (SI_NETBSD || SI_FREEBSD)
>> #define SANITIZER_INTERCEPT_TTYENT SI_NETBSD
>> #define SANITIZER_INTERCEPT_PROTOENT (SI_NETBSD || SI_LINUX)
>> -#define SANITIZER_INTERCEPT_PROTOENT_R (SI_LINUX_NOT_ANDROID)
>> +#define SANITIZER_INTERCEPT_PROTOENT_R SI_GLIBC
>> #define SANITIZER_INTERCEPT_NETENT SI_NETBSD
>> #define SANITIZER_INTERCEPT_SETVBUF \
>> (SI_NETBSD || SI_FREEBSD || SI_LINUX || SI_MAC)
>> @@ -583,7 +577,7 @@
>> #define SANITIZER_INTERCEPT_GETENTROPY SI_FREEBSD
>> #define SANITIZER_INTERCEPT_QSORT \
>> (SI_POSIX && !SI_IOSSIM && !SI_WATCHOS && !SI_TVOS && !SI_ANDROID)
>> -#define SANITIZER_INTERCEPT_QSORT_R (SI_LINUX && !SI_ANDROID)
>> +#define SANITIZER_INTERCEPT_QSORT_R SI_GLIBC
>> // sigaltstack on i386 macOS cannot be intercepted due to setjmp()
>> // calling it and assuming that it does not clobber registers.
>> #define SANITIZER_INTERCEPT_SIGALTSTACK \
>> @@ -591,4 +585,25 @@
>> #define SANITIZER_INTERCEPT_UNAME (SI_POSIX && !SI_FREEBSD)
>> #define SANITIZER_INTERCEPT___XUNAME SI_FREEBSD
>>
>> +// This macro gives a way for downstream users to override the above
>> +// interceptor macros irrespective of the platform they are on. They have
>> +// to do two things:
>> +// 1. Build compiler-rt with -DSANITIZER_OVERRIDE_INTERCEPTORS.
>> +// 2. Provide a header file named sanitizer_intercept_overriders.h in the
>> +// include path for their compiler-rt build.
>> +// An example of an overrider for strlen interceptor that one can list in
>> +// sanitizer_intercept_overriders.h is as follows:
>> +//
>> +// #ifdef SANITIZER_INTERCEPT_STRLEN
>> +// #undef SANITIZER_INTERCEPT_STRLEN
>> +// #define SANITIZER_INTERCEPT_STRLEN <value of choice>
>> +// #endif
>> +//
>> +// This "feature" is useful for downstream users who do not want some of
>> +// their libc funtions to be intercepted. They can selectively disable
>> +// interception of those functions.
>> +#ifdef SANITIZER_OVERRIDE_INTERCEPTORS
>> +#include <sanitizer_intercept_overriders.h>
>> +#endif
>> +
>> #endif // #ifndef SANITIZER_PLATFORM_INTERCEPTORS_H
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.cpp b/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.cpp
>> index b1c15be58de..b5a45ae72cd 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.cpp
>> @@ -35,7 +35,10 @@
>> #include <sys/stat.h>
>> #include <sys/statvfs.h>
>> #include <sys/time.h>
>> +#pragma clang diagnostic push
>> +#pragma clang diagnostic ignored "-W#warnings"
>> #include <sys/timeb.h>
>> +#pragma clang diagnostic pop
>> #include <sys/times.h>
>> #include <sys/timespec.h>
>> #include <sys/types.h>
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cpp b/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cpp
>> index f22f5039128..c51327e1269 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cpp
>> @@ -26,12 +26,9 @@
>>
>> // 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. Beware that with <sys/stat.h>, struct stat
>> -// takes the form of struct stat64 on 32-bit platforms if _FILE_OFFSET_BITS=64.
>> -// Also, for some platforms (e.g. mips) there are additional members in the
>> -// <sys/stat.h> struct stat:s.
>> +// fine with newer headers, too.
>> #include <linux/posix_types.h>
>> -#if defined(__x86_64__)
>> +#if defined(__x86_64__) || defined(__mips__)
>> #include <sys/stat.h>
>> #else
>> #define ino_t __kernel_ino_t
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp
>> index 1427cec48c4..35a690cba5c 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp
>> @@ -11,18 +11,19 @@
>> // Sizes and layouts of platform-specific POSIX data structures.
>> //===----------------------------------------------------------------------===//
>>
>> -#include "sanitizer_platform.h"
>> -
>> -#if SANITIZER_LINUX || SANITIZER_MAC
>> +#if defined(__linux__) || defined(__APPLE__)
>> // Tests in this file assume that off_t-dependent data structures match the
>> // libc ABI. For example, struct dirent here is what readdir() function (as
>> // exported from libc) returns, and not the user-facing "dirent", which
>> // depends on _FILE_OFFSET_BITS setting.
>> // To get this "true" dirent definition, we undefine _FILE_OFFSET_BITS below.
>> -#ifdef _FILE_OFFSET_BITS
>> #undef _FILE_OFFSET_BITS
>> #endif
>>
>> +// Must go after undef _FILE_OFFSET_BITS.
>> +#include "sanitizer_platform.h"
>> +
>> +#if SANITIZER_LINUX || SANITIZER_MAC
>> // Must go after undef _FILE_OFFSET_BITS.
>> #include "sanitizer_glibc_version.h"
>>
>> @@ -37,6 +38,7 @@
>> #include <pwd.h>
>> #include <signal.h>
>> #include <stddef.h>
>> +#include <stdio.h>
>> #include <sys/mman.h>
>> #include <sys/resource.h>
>> #include <sys/socket.h>
>> @@ -58,7 +60,6 @@
>> #endif
>>
>> #if !SANITIZER_ANDROID
>> -#include <fstab.h>
>> #include <sys/mount.h>
>> #include <sys/timeb.h>
>> #include <utmpx.h>
>> @@ -110,20 +111,31 @@ typedef struct user_fpregs elf_fpregset_t;
>> #include <wordexp.h>
>> #endif
>>
>> -#if SANITIZER_LINUX && !SANITIZER_ANDROID
>> -#include <glob.h>
>> -#include <obstack.h>
>> -#include <mqueue.h>
>> +#if SANITIZER_LINUX
>> +#if SANITIZER_GLIBC
>> +#include <fstab.h>
>> #include <net/if_ppp.h>
>> #include <netax25/ax25.h>
>> #include <netipx/ipx.h>
>> #include <netrom/netrom.h>
>> +#include <obstack.h>
>> #if HAVE_RPC_XDR_H
>> # include <rpc/xdr.h>
>> #endif
>> #include <scsi/scsi.h>
>> -#include <sys/mtio.h>
>> +#else
>> +#include <linux/if_ppp.h>
>> +#include <linux/kd.h>
>> +#include <linux/ppp_defs.h>
>> +#endif // SANITIZER_GLIBC
>> +
>> +#if SANITIZER_ANDROID
>> +#include <linux/mtio.h>
>> +#else
>> +#include <glob.h>
>> +#include <mqueue.h>
>> #include <sys/kd.h>
>> +#include <sys/mtio.h>
>> #include <sys/shm.h>
>> #include <sys/statvfs.h>
>> #include <sys/timex.h>
>> @@ -142,20 +154,14 @@ typedef struct user_fpregs elf_fpregset_t;
>> #include <sys/msg.h>
>> #include <sys/ipc.h>
>> #include <crypt.h>
>> -#endif // SANITIZER_LINUX && !SANITIZER_ANDROID
>> +#endif // SANITIZER_ANDROID
>>
>> -#if SANITIZER_ANDROID
>> -#include <linux/kd.h>
>> -#include <linux/mtio.h>
>> -#include <linux/ppp_defs.h>
>> -#include <linux/if_ppp.h>
>> -#endif
>> -
>> -#if SANITIZER_LINUX
>> #include <link.h>
>> #include <sys/vfs.h>
>> #include <sys/epoll.h>
>> #include <linux/capability.h>
>> +#else
>> +#include <fstab.h>
>> #endif // SANITIZER_LINUX
>>
>> #if SANITIZER_MAC
>> @@ -202,8 +208,11 @@ namespace __sanitizer {
>> unsigned struct_statfs64_sz = sizeof(struct statfs64);
>> #endif // (SANITIZER_MAC && !TARGET_CPU_ARM64) && !SANITIZER_IOS
>>
>> -#if !SANITIZER_ANDROID
>> +#if SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_MAC
>> unsigned struct_fstab_sz = sizeof(struct fstab);
>> +#endif // SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD ||
>> + // SANITIZER_MAC
>> +#if !SANITIZER_ANDROID
>> unsigned struct_statfs_sz = sizeof(struct statfs);
>> unsigned struct_sockaddr_sz = sizeof(struct sockaddr);
>> unsigned ucontext_t_sz = sizeof(ucontext_t);
>> @@ -299,7 +308,7 @@ unsigned struct_ElfW_Phdr_sz = sizeof(ElfW(Phdr));
>> unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
>> #endif
>>
>> -#if SANITIZER_LINUX && !SANITIZER_ANDROID
>> +#if SANITIZER_GLIBC
>> int glob_nomatch = GLOB_NOMATCH;
>> int glob_altdirfunc = GLOB_ALTDIRFUNC;
>> #endif
>> @@ -422,7 +431,9 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
>> unsigned struct_input_id_sz = sizeof(struct input_id);
>> unsigned struct_mtpos_sz = sizeof(struct mtpos);
>> unsigned struct_rtentry_sz = sizeof(struct rtentry);
>> +#if SANITIZER_GLIBC || SANITIZER_ANDROID
>> unsigned struct_termio_sz = sizeof(struct termio);
>> +#endif
>> unsigned struct_vt_consize_sz = sizeof(struct vt_consize);
>> unsigned struct_vt_sizes_sz = sizeof(struct vt_sizes);
>> unsigned struct_vt_stat_sz = sizeof(struct vt_stat);
>> @@ -447,7 +458,7 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
>> unsigned struct_vt_mode_sz = sizeof(struct vt_mode);
>> #endif // SANITIZER_LINUX
>>
>> -#if SANITIZER_LINUX && !SANITIZER_ANDROID
>> +#if SANITIZER_GLIBC
>> unsigned struct_ax25_parms_struct_sz = sizeof(struct ax25_parms_struct);
>> unsigned struct_cyclades_monitor_sz = sizeof(struct cyclades_monitor);
>> #if EV_VERSION > (0x010000)
>> @@ -470,12 +481,10 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
>> unsigned struct_sockaddr_ax25_sz = sizeof(struct sockaddr_ax25);
>> unsigned struct_unimapdesc_sz = sizeof(struct unimapdesc);
>> unsigned struct_unimapinit_sz = sizeof(struct unimapinit);
>> -#endif // SANITIZER_LINUX && !SANITIZER_ANDROID
>>
>> -#if SANITIZER_LINUX && !SANITIZER_ANDROID
>> unsigned struct_audio_buf_info_sz = sizeof(struct audio_buf_info);
>> unsigned struct_ppp_stats_sz = sizeof(struct ppp_stats);
>> -#endif // (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
>> +#endif // SANITIZER_GLIBC
>>
>> #if !SANITIZER_ANDROID && !SANITIZER_MAC
>> unsigned struct_sioc_sg_req_sz = sizeof(struct sioc_sg_req);
>> @@ -881,6 +890,7 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
>> unsigned IOCTL_PIO_UNIMAP = PIO_UNIMAP;
>> unsigned IOCTL_PIO_UNIMAPCLR = PIO_UNIMAPCLR;
>> unsigned IOCTL_PIO_UNISCRNMAP = PIO_UNISCRNMAP;
>> +#if SANITIZER_GLIBC
>> unsigned IOCTL_SCSI_IOCTL_GET_IDLUN = SCSI_IOCTL_GET_IDLUN;
>> unsigned IOCTL_SCSI_IOCTL_PROBE_HOST = SCSI_IOCTL_PROBE_HOST;
>> unsigned IOCTL_SCSI_IOCTL_TAGGED_DISABLE = SCSI_IOCTL_TAGGED_DISABLE;
>> @@ -899,6 +909,7 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
>> unsigned IOCTL_SIOCNRGETPARMS = SIOCNRGETPARMS;
>> unsigned IOCTL_SIOCNRRTCTL = SIOCNRRTCTL;
>> unsigned IOCTL_SIOCNRSETPARMS = SIOCNRSETPARMS;
>> +#endif
>> unsigned IOCTL_TIOCGSERIAL = TIOCGSERIAL;
>> unsigned IOCTL_TIOCSERGETMULTI = TIOCSERGETMULTI;
>> unsigned IOCTL_TIOCSERSETMULTI = TIOCSERSETMULTI;
>> @@ -969,7 +980,7 @@ CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phdr);
>> CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phnum);
>> #endif // SANITIZER_LINUX || SANITIZER_FREEBSD
>>
>> -#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
>> +#if SANITIZER_GLIBC || SANITIZER_FREEBSD
>> CHECK_TYPE_SIZE(glob_t);
>> CHECK_SIZE_AND_OFFSET(glob_t, gl_pathc);
>> CHECK_SIZE_AND_OFFSET(glob_t, gl_pathv);
>> @@ -980,7 +991,7 @@ CHECK_SIZE_AND_OFFSET(glob_t, gl_readdir);
>> CHECK_SIZE_AND_OFFSET(glob_t, gl_opendir);
>> CHECK_SIZE_AND_OFFSET(glob_t, gl_lstat);
>> CHECK_SIZE_AND_OFFSET(glob_t, gl_stat);
>> -#endif
>> +#endif // SANITIZER_GLIBC || SANITIZER_FREEBSD
>>
>> CHECK_TYPE_SIZE(addrinfo);
>> CHECK_SIZE_AND_OFFSET(addrinfo, ai_flags);
>> @@ -1003,17 +1014,27 @@ CHECK_TYPE_SIZE(iovec);
>> CHECK_SIZE_AND_OFFSET(iovec, iov_base);
>> CHECK_SIZE_AND_OFFSET(iovec, iov_len);
>>
>> +// In POSIX, int msg_iovlen; socklen_t msg_controllen; socklen_t cmsg_len; but
>> +// many implementations don't conform to the standard. Since we pick the
>> +// non-conforming glibc definition, exclude the checks for musl (incompatible
>> +// sizes but compatible offsets).
>> CHECK_TYPE_SIZE(msghdr);
>> CHECK_SIZE_AND_OFFSET(msghdr, msg_name);
>> CHECK_SIZE_AND_OFFSET(msghdr, msg_namelen);
>> CHECK_SIZE_AND_OFFSET(msghdr, msg_iov);
>> +#if SANITIZER_GLIBC || SANITIZER_ANDROID
>> CHECK_SIZE_AND_OFFSET(msghdr, msg_iovlen);
>> +#endif
>> CHECK_SIZE_AND_OFFSET(msghdr, msg_control);
>> +#if SANITIZER_GLIBC || SANITIZER_ANDROID
>> CHECK_SIZE_AND_OFFSET(msghdr, msg_controllen);
>> +#endif
>> CHECK_SIZE_AND_OFFSET(msghdr, msg_flags);
>>
>> CHECK_TYPE_SIZE(cmsghdr);
>> +#if SANITIZER_GLIBC || SANITIZER_ANDROID
>> CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_len);
>> +#endif
>> CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_level);
>> CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_type);
>>
>> @@ -1121,7 +1142,7 @@ CHECK_SIZE_AND_OFFSET(mntent, mnt_passno);
>>
>> CHECK_TYPE_SIZE(ether_addr);
>>
>> -#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
>> +#if SANITIZER_GLIBC || SANITIZER_FREEBSD
>> CHECK_TYPE_SIZE(ipc_perm);
>> # if SANITIZER_FREEBSD
>> CHECK_SIZE_AND_OFFSET(ipc_perm, key);
>> @@ -1183,7 +1204,7 @@ CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_dstaddr);
>> CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_data);
>> #endif
>>
>> -#if SANITIZER_LINUX
>> +#if SANITIZER_GLIBC || SANITIZER_ANDROID
>> COMPILER_CHECK(sizeof(__sanitizer_struct_mallinfo) == sizeof(struct mallinfo));
>> #endif
>>
>> @@ -1233,7 +1254,7 @@ COMPILER_CHECK(__sanitizer_XDR_DECODE == XDR_DECODE);
>> COMPILER_CHECK(__sanitizer_XDR_FREE == XDR_FREE);
>> #endif
>>
>> -#if SANITIZER_LINUX && !SANITIZER_ANDROID
>> +#if SANITIZER_GLIBC
>> COMPILER_CHECK(sizeof(__sanitizer_FILE) <= sizeof(FILE));
>> CHECK_SIZE_AND_OFFSET(FILE, _flags);
>> CHECK_SIZE_AND_OFFSET(FILE, _IO_read_ptr);
>> @@ -1250,9 +1271,7 @@ CHECK_SIZE_AND_OFFSET(FILE, _IO_save_end);
>> CHECK_SIZE_AND_OFFSET(FILE, _markers);
>> CHECK_SIZE_AND_OFFSET(FILE, _chain);
>> CHECK_SIZE_AND_OFFSET(FILE, _fileno);
>> -#endif
>>
>> -#if SANITIZER_LINUX && !SANITIZER_ANDROID
>> COMPILER_CHECK(sizeof(__sanitizer__obstack_chunk) <= sizeof(_obstack_chunk));
>> CHECK_SIZE_AND_OFFSET(_obstack_chunk, limit);
>> CHECK_SIZE_AND_OFFSET(_obstack_chunk, prev);
>> @@ -1267,7 +1286,7 @@ CHECK_SIZE_AND_OFFSET(cookie_io_functions_t, read);
>> CHECK_SIZE_AND_OFFSET(cookie_io_functions_t, write);
>> CHECK_SIZE_AND_OFFSET(cookie_io_functions_t, seek);
>> CHECK_SIZE_AND_OFFSET(cookie_io_functions_t, close);
>> -#endif
>> +#endif // SANITIZER_GLIBC
>>
>> #if SANITIZER_LINUX || SANITIZER_FREEBSD
>> CHECK_TYPE_SIZE(sem_t);
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h
>> index 0812039b038..836b178c131 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h
>> +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h
>> @@ -83,7 +83,7 @@ const unsigned struct_kernel_stat64_sz = 104;
>> #elif defined(__mips__)
>> const unsigned struct_kernel_stat_sz = SANITIZER_ANDROID
>> ? FIRST_32_SECOND_64(104, 128)
>> - : FIRST_32_SECOND_64(144, 216);
>> + : FIRST_32_SECOND_64(160, 216);
>> const unsigned struct_kernel_stat64_sz = 104;
>> #elif defined(__s390__) && !defined(__s390x__)
>> const unsigned struct_kernel_stat_sz = 64;
>> @@ -443,6 +443,8 @@ struct __sanitizer_cmsghdr {
>> int cmsg_type;
>> };
>> #else
>> +// In POSIX, int msg_iovlen; socklen_t msg_controllen; socklen_t cmsg_len; but
>> +// many implementations don't conform to the standard.
>> struct __sanitizer_msghdr {
>> void *msg_name;
>> unsigned msg_namelen;
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_posix.cpp b/libsanitizer/sanitizer_common/sanitizer_posix.cpp
>> index 2e080098283..f8457a6aac4 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_posix.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_posix.cpp
>> @@ -275,8 +275,8 @@ void ReportFile::Write(const char *buffer, uptr length) {
>>
>> bool GetCodeRangeForFile(const char *module, uptr *start, uptr *end) {
>> MemoryMappingLayout proc_maps(/*cache_enabled*/false);
>> - InternalScopedString buff(kMaxPathLength);
>> - MemoryMappedSegment segment(buff.data(), kMaxPathLength);
>> + InternalMmapVector<char> buff(kMaxPathLength);
>> + MemoryMappedSegment segment(buff.data(), buff.size());
>> while (proc_maps.Next(&segment)) {
>> if (segment.IsExecutable() &&
>> internal_strcmp(module, segment.filename) == 0) {
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_posix.h b/libsanitizer/sanitizer_common/sanitizer_posix.h
>> index e1a2b48e5cd..b65dae64476 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_posix.h
>> +++ b/libsanitizer/sanitizer_common/sanitizer_posix.h
>> @@ -40,6 +40,10 @@ uptr internal_write(fd_t fd, const void *buf, uptr count);
>> uptr internal_mmap(void *addr, uptr length, int prot, int flags,
>> int fd, u64 offset);
>> uptr internal_munmap(void *addr, uptr length);
>> +#if SANITIZER_LINUX
>> +uptr internal_mremap(void *old_address, uptr old_size, uptr new_size, int flags,
>> + void *new_address);
>> +#endif
>> int internal_mprotect(void *addr, uptr length, int prot);
>> int internal_madvise(uptr addr, uptr length, int advice);
>>
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp
>> index 7ff48c35851..d1d8e509c4d 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp
>> @@ -143,7 +143,7 @@ void Abort() {
>> if (GetHandleSignalMode(SIGABRT) != kHandleSignalNo) {
>> struct sigaction sigact;
>> internal_memset(&sigact, 0, sizeof(sigact));
>> - sigact.sa_sigaction = (sa_sigaction_t)SIG_DFL;
>> + sigact.sa_handler = SIG_DFL;
>> internal_sigaction(SIGABRT, &sigact, nullptr);
>> }
>> #endif
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_printf.cpp b/libsanitizer/sanitizer_common/sanitizer_printf.cpp
>> index a032787114b..5d16dfde678 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_printf.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_printf.cpp
>> @@ -249,26 +249,21 @@ static void NOINLINE SharedPrintfCodeNoBuffer(bool append_pid,
>> va_list args) {
>> va_list args2;
>> va_copy(args2, args);
>> - const int kLen = 16 * 1024;
>> - int needed_length;
>> + InternalMmapVector<char> v;
>> + int needed_length = 0;
>> char *buffer = local_buffer;
>> // First try to print a message using a local buffer, and then fall back to
>> // mmaped buffer.
>> - for (int use_mmap = 0; use_mmap < 2; use_mmap++) {
>> + for (int use_mmap = 0;; use_mmap++) {
>> if (use_mmap) {
>> va_end(args);
>> va_copy(args, args2);
>> - buffer = (char*)MmapOrDie(kLen, "Report");
>> - buffer_size = kLen;
>> + v.resize(needed_length + 1);
>> + buffer_size = v.capacity();
>> + v.resize(buffer_size);
>> + buffer = &v[0];
>> }
>> needed_length = 0;
>> - // Check that data fits into the current buffer.
>> -# define CHECK_NEEDED_LENGTH \
>> - if (needed_length >= buffer_size) { \
>> - if (!use_mmap) continue; \
>> - RAW_CHECK_MSG(needed_length < kLen, \
>> - "Buffer in Report is too short!\n"); \
>> - }
>> // Fuchsia's logging infrastructure always keeps track of the logging
>> // process, thread, and timestamp, so never prepend such information.
>> if (!SANITIZER_FUCHSIA && append_pid) {
>> @@ -277,18 +272,20 @@ static void NOINLINE SharedPrintfCodeNoBuffer(bool append_pid,
>> if (common_flags()->log_exe_name && exe_name) {
>> needed_length += internal_snprintf(buffer, buffer_size,
>> "==%s", exe_name);
>> - CHECK_NEEDED_LENGTH
>> + if (needed_length >= buffer_size)
>> + continue;
>> }
>> needed_length += internal_snprintf(
>> buffer + needed_length, buffer_size - needed_length, "==%d==", pid);
>> - CHECK_NEEDED_LENGTH
>> + if (needed_length >= buffer_size)
>> + continue;
>> }
>> needed_length += VSNPrintf(buffer + needed_length,
>> buffer_size - needed_length, format, args);
>> - CHECK_NEEDED_LENGTH
>> + if (needed_length >= buffer_size)
>> + continue;
>> // If the message fit into the buffer, print it and exit.
>> break;
>> -# undef CHECK_NEEDED_LENGTH
>> }
>> RawWrite(buffer);
>>
>> @@ -297,9 +294,6 @@ static void NOINLINE SharedPrintfCodeNoBuffer(bool append_pid,
>> CallPrintfAndReportCallback(buffer);
>> LogMessageOnPrintf(buffer);
>>
>> - // If we had mapped any memory, clean up.
>> - if (buffer != local_buffer)
>> - UnmapOrDie((void *)buffer, buffer_size);
>> va_end(args2);
>> }
>>
>> @@ -346,13 +340,24 @@ int internal_snprintf(char *buffer, uptr length, const char *format, ...) {
>>
>> FORMAT(2, 3)
>> 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_);
>> - CHECK_LT(length_, size());
>> + uptr prev_len = length();
>> +
>> + while (true) {
>> + buffer_.resize(buffer_.capacity());
>> +
>> + va_list args;
>> + va_start(args, format);
>> + uptr sz = VSNPrintf(buffer_.data() + prev_len, buffer_.size() - prev_len,
>> + format, args);
>> + va_end(args);
>> + if (sz < buffer_.size() - prev_len) {
>> + buffer_.resize(prev_len + sz + 1);
>> + break;
>> + }
>> +
>> + buffer_.reserve(buffer_.capacity() * 2);
>> + }
>> + CHECK_EQ(buffer_[length()], '\0');
>> }
>>
>> } // namespace __sanitizer
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_procmaps_common.cpp b/libsanitizer/sanitizer_common/sanitizer_procmaps_common.cpp
>> index f2cfcffaf47..1b7dd46d8de 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_procmaps_common.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_procmaps_common.cpp
>> @@ -120,7 +120,7 @@ void MemoryMappingLayout::LoadFromCache() {
>> void MemoryMappingLayout::DumpListOfModules(
>> InternalMmapVectorNoCtor<LoadedModule> *modules) {
>> Reset();
>> - InternalScopedString module_name(kMaxPathLength);
>> + InternalMmapVector<char> module_name(kMaxPathLength);
>> MemoryMappedSegment segment(module_name.data(), module_name.size());
>> for (uptr i = 0; Next(&segment); i++) {
>> const char *cur_name = segment.filename;
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_procmaps_mac.cpp b/libsanitizer/sanitizer_common/sanitizer_procmaps_mac.cpp
>> index d02afcfe87a..1f53e3e46d8 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_procmaps_mac.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_procmaps_mac.cpp
>> @@ -354,8 +354,8 @@ bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) {
>> void MemoryMappingLayout::DumpListOfModules(
>> InternalMmapVectorNoCtor<LoadedModule> *modules) {
>> Reset();
>> - InternalScopedString module_name(kMaxPathLength);
>> - MemoryMappedSegment segment(module_name.data(), kMaxPathLength);
>> + InternalMmapVector<char> module_name(kMaxPathLength);
>> + MemoryMappedSegment segment(module_name.data(), module_name.size());
>> MemoryMappedSegmentData data;
>> segment.data_ = &data;
>> while (Next(&segment)) {
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_procmaps_solaris.cpp b/libsanitizer/sanitizer_common/sanitizer_procmaps_solaris.cpp
>> index 4063ec8deaa..bf813f235bb 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_procmaps_solaris.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_procmaps_solaris.cpp
>> @@ -9,13 +9,13 @@
>> // Information about the process mappings (Solaris-specific parts).
>> //===----------------------------------------------------------------------===//
>>
>> +// Before Solaris 11.4, <procfs.h> doesn't work in a largefile environment.
>> +#undef _FILE_OFFSET_BITS
>> #include "sanitizer_platform.h"
>> #if SANITIZER_SOLARIS
>> #include "sanitizer_common.h"
>> #include "sanitizer_procmaps.h"
>>
>> -// Before Solaris 11.4, <procfs.h> doesn't work in a largefile environment.
>> -#undef _FILE_OFFSET_BITS
>> #include <procfs.h>
>> #include <limits.h>
>>
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_ptrauth.h b/libsanitizer/sanitizer_common/sanitizer_ptrauth.h
>> index a288068bf94..52003546948 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_ptrauth.h
>> +++ b/libsanitizer/sanitizer_common/sanitizer_ptrauth.h
>> @@ -11,6 +11,24 @@
>>
>> #if __has_feature(ptrauth_calls)
>> #include <ptrauth.h>
>> +#elif defined(__ARM_FEATURE_PAC_DEFAULT) && !defined(__APPLE__)
>> +inline unsigned long ptrauth_strip(void* __value, unsigned int __key) {
>> + // On the stack the link register is protected with Pointer
>> + // Authentication Code when compiled with -mbranch-protection.
>> + // Let's stripping the PAC unconditionally because xpaclri is in
>> + // the NOP space so will do nothing when it is not enabled or not available.
>> + unsigned long ret;
>> + asm volatile(
>> + "mov x30, %1\n\t"
>> + "hint #7\n\t" // xpaclri
>> + "mov %0, x30\n\t"
>> + : "=r"(ret)
>> + : "r"(__value)
>> + : "x30");
>> + return ret;
>> +}
>> +#define ptrauth_auth_data(__value, __old_key, __old_data) __value
>> +#define ptrauth_string_discriminator(__string) ((int)0)
>> #else
>> // Copied from <ptrauth.h>
>> #define ptrauth_strip(__value, __key) __value
>> @@ -18,6 +36,6 @@
>> #define ptrauth_string_discriminator(__string) ((int)0)
>> #endif
>>
>> -#define STRIP_PC(pc) ((uptr)ptrauth_strip(pc, 0))
>> +#define STRIP_PAC_PC(pc) ((uptr)ptrauth_strip(pc, 0))
>>
>> #endif // SANITIZER_PTRAUTH_H
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_stackdepot.cpp b/libsanitizer/sanitizer_common/sanitizer_stackdepot.cpp
>> index 4692f50d323..44a95214e38 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_stackdepot.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_stackdepot.cpp
>> @@ -145,8 +145,7 @@ StackTrace StackDepotReverseMap::Get(u32 id) {
>> if (!map_.size())
>> return StackTrace();
>> IdDescPair pair = {id, nullptr};
>> - uptr idx =
>> - InternalLowerBound(map_, 0, map_.size(), pair, IdDescPair::IdComparator);
>> + uptr idx = InternalLowerBound(map_, pair, IdDescPair::IdComparator);
>> if (idx > map_.size() || map_[idx].id != id)
>> return StackTrace();
>> return map_[idx].desc->load();
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp b/libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp
>> index b28fc1cf736..07e4409f4a5 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp
>> @@ -15,6 +15,7 @@
>> #include "sanitizer_common.h"
>> #include "sanitizer_flags.h"
>> #include "sanitizer_platform.h"
>> +#include "sanitizer_ptrauth.h"
>>
>> namespace __sanitizer {
>>
>> @@ -84,8 +85,8 @@ static inline uhwptr *GetCanonicFrame(uptr bp,
>> // Nope, this does not look right either. This means the frame after next does
>> // not have a valid frame pointer, but we can still extract the caller PC.
>> // Unfortunately, there is no way to decide between GCC and LLVM frame
>> - // layouts. Assume GCC.
>> - return bp_prev - 1;
>> + // layouts. Assume LLVM.
>> + return bp_prev;
>> #else
>> return (uhwptr*)bp;
>> #endif
>> @@ -108,28 +109,21 @@ void BufferedStackTrace::UnwindFast(uptr pc, uptr bp, uptr stack_top,
>> IsAligned((uptr)frame, sizeof(*frame)) &&
>> size < max_depth) {
>> #ifdef __powerpc__
>> - // PowerPC ABIs specify that the return address is saved on the
>> - // *caller's* stack frame. Thus we must dereference the back chain
>> - // to find the caller frame before extracting it.
>> + // PowerPC ABIs specify that the return address is saved at offset
>> + // 16 of the *caller's* stack frame. Thus we must dereference the
>> + // back chain to find the caller frame before extracting it.
>> uhwptr *caller_frame = (uhwptr*)frame[0];
>> if (!IsValidFrame((uptr)caller_frame, stack_top, bottom) ||
>> !IsAligned((uptr)caller_frame, sizeof(uhwptr)))
>> break;
>> - // For most ABIs the offset where the return address is saved is two
>> - // register sizes. The exception is the SVR4 ABI, which uses an
>> - // offset of only one register size.
>> -#ifdef _CALL_SYSV
>> - uhwptr pc1 = caller_frame[1];
>> -#else
>> uhwptr pc1 = caller_frame[2];
>> -#endif
>> #elif defined(__s390__)
>> uhwptr pc1 = frame[14];
>> #elif defined(__riscv)
>> // frame[-1] contains the return address
>> uhwptr pc1 = frame[-1];
>> #else
>> - uhwptr pc1 = frame[1];
>> + uhwptr pc1 = STRIP_PAC_PC((void *)frame[1]);
>> #endif
>> // Let's assume that any pointer in the 0th page (i.e. <0x1000 on i386 and
>> // x86_64) is invalid and stop unwinding here. If we're adding support for
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace.h b/libsanitizer/sanitizer_common/sanitizer_stacktrace.h
>> index 0350fe84b04..15616f899d0 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_stacktrace.h
>> +++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace.h
>> @@ -67,8 +67,6 @@ struct StackTrace {
>> static uptr GetCurrentPc();
>> static inline uptr GetPreviousInstructionPc(uptr pc);
>> static uptr GetNextInstructionPc(uptr pc);
>> - typedef bool (*SymbolizeCallback)(const void *pc, char *out_buffer,
>> - int out_size);
>> };
>>
>> // Performance-critical, must be in the header.
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_stacktrace_libcdep.cpp
>> index 7808ba9b0f5..738633209f0 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_stacktrace_libcdep.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace_libcdep.cpp
>> @@ -23,8 +23,8 @@ void StackTrace::Print() const {
>> Printf(" <empty stack>\n\n");
>> return;
>> }
>> - InternalScopedString frame_desc(GetPageSizeCached() * 2);
>> - InternalScopedString dedup_token(GetPageSizeCached());
>> + InternalScopedString frame_desc;
>> + InternalScopedString dedup_token;
>> int dedup_frames = common_flags()->dedup_token_length;
>> bool symbolize = RenderNeedsSymbolization(common_flags()->stack_trace_format);
>> uptr frame_num = 0;
>> @@ -125,7 +125,7 @@ void __sanitizer_symbolize_pc(uptr pc, const char *fmt, char *out_buf,
>> out_buf[out_buf_size - 1] = 0;
>> return;
>> }
>> - InternalScopedString frame_desc(GetPageSizeCached());
>> + InternalScopedString frame_desc;
>> uptr frame_num = 0;
>> // Reserve one byte for the final 0.
>> char *out_end = out_buf + out_buf_size - 1;
>> @@ -156,7 +156,7 @@ void __sanitizer_symbolize_global(uptr data_addr, const char *fmt,
>> out_buf[0] = 0;
>> DataInfo DI;
>> if (!Symbolizer::GetOrInit()->SymbolizeData(data_addr, &DI)) return;
>> - InternalScopedString data_desc(GetPageSizeCached());
>> + InternalScopedString data_desc;
>> RenderData(&data_desc, fmt, &DI, common_flags()->strip_path_prefix);
>> internal_strncpy(out_buf, data_desc.data(), out_buf_size);
>> out_buf[out_buf_size - 1] = 0;
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp
>> index 0f1cadfeae3..53cfddcfbe0 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp
>> @@ -490,6 +490,9 @@ typedef user_regs_struct regs_struct;
>> #ifndef NT_X86_XSTATE
>> #define NT_X86_XSTATE 0x202
>> #endif
>> +#ifndef PTRACE_GETREGSET
>> +#define PTRACE_GETREGSET 0x4204
>> +#endif
>> // Compiler may use FP registers to store pointers.
>> static constexpr uptr kExtraRegs[] = {NT_X86_XSTATE, NT_FPREGSET};
>>
>> @@ -513,6 +516,8 @@ static constexpr uptr kExtraRegs[] = {0};
>>
>> #elif SANITIZER_RISCV64
>> typedef struct user_regs_struct regs_struct;
>> +// sys/ucontext.h already defines REG_SP as 2. Undefine it first.
>> +#undef REG_SP
>> #define REG_SP sp
>> static constexpr uptr kExtraRegs[] = {0};
>> #define ARCH_IOVEC_FOR_GETREGSET
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_suppressions.cpp b/libsanitizer/sanitizer_common/sanitizer_suppressions.cpp
>> index 44c83a66c5f..a674034b8e2 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_suppressions.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_suppressions.cpp
>> @@ -34,7 +34,7 @@ SuppressionContext::SuppressionContext(const char *suppression_types[],
>> static bool GetPathAssumingFileIsRelativeToExec(const char *file_path,
>> /*out*/char *new_file_path,
>> uptr new_file_path_size) {
>> - InternalScopedString exec(kMaxPathLength);
>> + InternalMmapVector<char> exec(kMaxPathLength);
>> if (ReadBinaryNameCached(exec.data(), exec.size())) {
>> const char *file_name_pos = StripModuleName(exec.data());
>> uptr path_to_exec_len = file_name_pos - exec.data();
>> @@ -69,7 +69,7 @@ void SuppressionContext::ParseFromFile(const char *filename) {
>> if (filename[0] == '\0')
>> return;
>>
>> - InternalScopedString new_file_path(kMaxPathLength);
>> + InternalMmapVector<char> new_file_path(kMaxPathLength);
>> filename = FindFile(filename, new_file_path.data(), new_file_path.size());
>>
>> // Read the file.
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cpp
>> index 710da4c1cec..98418b426c3 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cpp
>> @@ -356,7 +356,7 @@ void ParseSymbolizePCOutput(const char *str, SymbolizedStack *res) {
>> InternalFree(info->function);
>> info->function = 0;
>> }
>> - if (0 == internal_strcmp(info->file, "??")) {
>> + if (info->file && 0 == internal_strcmp(info->file, "??")) {
>> InternalFree(info->file);
>> info->file = 0;
>> }
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_markup.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_markup.cpp
>> index 30cba08ed53..01edef9c1aa 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_markup.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_markup.cpp
>> @@ -54,6 +54,10 @@ bool Symbolizer::GetModuleNameAndOffsetForPC(uptr pc, const char **module_name,
>> return false;
>> }
>>
>> +// This is mainly used by hwasan for online symbolization. This isn't needed
>> +// since hwasan can always just dump stack frames for offline symbolization.
>> +bool Symbolizer::SymbolizeFrame(uptr addr, FrameInfo *info) { return false; }
>> +
>> // This is used in some places for suppression checking, which we
>> // don't really support for Fuchsia. It's also used in UBSan to
>> // identify a PC location to a function name, so we always fill in
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp
>> index 4dd5cc3ad7c..4cd4b4636f0 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp
>> @@ -400,11 +400,20 @@ const char *Symbolizer::PlatformDemangle(const char *name) {
>>
>> static SymbolizerTool *ChooseExternalSymbolizer(LowLevelAllocator *allocator) {
>> const char *path = common_flags()->external_symbolizer_path;
>> +
>> + if (path && internal_strchr(path, '%')) {
>> + char *new_path = (char *)InternalAlloc(kMaxPathLength);
>> + SubstituteForFlagValue(path, new_path, kMaxPathLength);
>> + path = new_path;
>> + }
>> +
>> const char *binary_name = path ? StripModuleName(path) : "";
>> + static const char kLLVMSymbolizerPrefix[] = "llvm-symbolizer";
>> if (path && path[0] == '\0') {
>> VReport(2, "External symbolizer is explicitly disabled.\n");
>> return nullptr;
>> - } else if (!internal_strcmp(binary_name, "llvm-symbolizer")) {
>> + } else if (!internal_strncmp(binary_name, kLLVMSymbolizerPrefix,
>> + internal_strlen(kLLVMSymbolizerPrefix))) {
>> VReport(2, "Using llvm-symbolizer at user-specified path: %s\n", path);
>> return new(*allocator) LLVMSymbolizer(path, allocator);
>> } else if (!internal_strcmp(binary_name, "atos")) {
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_report.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_report.cpp
>> index 06301b83ea1..9287993e665 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_report.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_report.cpp
>> @@ -31,7 +31,7 @@ namespace __sanitizer {
>> void ReportErrorSummary(const char *error_type, const AddressInfo &info,
>> const char *alt_tool_name) {
>> if (!common_flags()->print_summary) return;
>> - InternalScopedString buff(kMaxSummaryLength);
>> + InternalScopedString buff;
>> buff.append("%s ", error_type);
>> RenderFrame(&buff, "%L %F", 0, info.address, &info,
>> common_flags()->symbolize_vs_style,
>> @@ -150,7 +150,7 @@ static void PrintMemoryByte(InternalScopedString *str, const char *before,
>> static void MaybeDumpInstructionBytes(uptr pc) {
>> if (!common_flags()->dump_instruction_bytes || (pc < GetPageSizeCached()))
>> return;
>> - InternalScopedString str(1024);
>> + InternalScopedString str;
>> str.append("First 16 instruction bytes at pc: ");
>> if (IsAccessibleMemoryRange(pc, 16)) {
>> for (int i = 0; i < 16; ++i) {
>> @@ -211,7 +211,7 @@ static void ReportDeadlySignalImpl(const SignalContext &sig, u32 tid,
>> Report("The signal is caused by a %s memory access.\n", access_type);
>> if (!sig.is_true_faulting_addr)
>> Report("Hint: this fault was caused by a dereference of a high value "
>> - "address (see register values below). Dissassemble the provided "
>> + "address (see register values below). Disassemble the provided "
>> "pc to learn which register was used.\n");
>> else if (sig.addr < GetPageSizeCached())
>> Report("Hint: address points to the zero page.\n");
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cpp
>> index 48fa2d1033a..702d901353d 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cpp
>> @@ -136,9 +136,10 @@ void InitializeDbgHelpIfNeeded() {
>> bool WinSymbolizerTool::SymbolizePC(uptr addr, SymbolizedStack *frame) {
>> InitializeDbgHelpIfNeeded();
>>
>> - // See http://msdn.microsoft.com/en-us/library/ms680578(VS.85).aspx
>> - char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(CHAR)];
>> - PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer;
>> + // See https://docs.microsoft.com/en-us/windows/win32/debug/retrieving-symbol-information-by-address
>> + InternalMmapVector<char> buffer(sizeof(SYMBOL_INFO) +
>> + MAX_SYM_NAME * sizeof(CHAR));
>> + PSYMBOL_INFO symbol = (PSYMBOL_INFO)&buffer[0];
>> symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
>> symbol->MaxNameLen = MAX_SYM_NAME;
>> DWORD64 offset = 0;
>> @@ -223,7 +224,7 @@ bool SymbolizerProcess::StartSymbolizerSubprocess() {
>> // Compute the command line. Wrap double quotes around everything.
>> const char *argv[kArgVMax];
>> GetArgV(path_, argv);
>> - InternalScopedString command_line(kMaxPathLength * 3);
>> + InternalScopedString command_line;
>> for (int i = 0; argv[i]; i++) {
>> const char *arg = argv[i];
>> int arglen = internal_strlen(arg);
>> @@ -281,8 +282,15 @@ static void ChooseSymbolizerTools(IntrusiveList<SymbolizerTool> *list,
>> return;
>> }
>>
>> - // Add llvm-symbolizer in case the binary has dwarf.
>> + // Add llvm-symbolizer.
>> const char *user_path = common_flags()->external_symbolizer_path;
>> +
>> + if (user_path && internal_strchr(user_path, '%')) {
>> + char *new_path = (char *)InternalAlloc(kMaxPathLength);
>> + SubstituteForFlagValue(user_path, new_path, kMaxPathLength);
>> + user_path = new_path;
>> + }
>> +
>> const char *path =
>> user_path ? user_path : FindPathToBinary("llvm-symbolizer.exe");
>> if (path) {
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_termination.cpp b/libsanitizer/sanitizer_common/sanitizer_termination.cpp
>> index 84be6fc3234..6a54734353c 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_termination.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_termination.cpp
>> @@ -59,26 +59,31 @@ void NORETURN Die() {
>> internal__exit(common_flags()->exitcode);
>> }
>>
>> -static CheckFailedCallbackType CheckFailedCallback;
>> -void SetCheckFailedCallback(CheckFailedCallbackType callback) {
>> - CheckFailedCallback = callback;
>> +static void (*CheckUnwindCallback)();
>> +void SetCheckUnwindCallback(void (*callback)()) {
>> + CheckUnwindCallback = callback;
>> }
>>
>> -const int kSecondsToSleepWhenRecursiveCheckFailed = 2;
>> -
>> void NORETURN CheckFailed(const char *file, int line, const char *cond,
>> u64 v1, u64 v2) {
>> - static atomic_uint32_t num_calls;
>> - if (atomic_fetch_add(&num_calls, 1, memory_order_relaxed) > 10) {
>> - SleepForSeconds(kSecondsToSleepWhenRecursiveCheckFailed);
>> + u32 tid = GetTid();
>> + Printf("%s: CHECK failed: %s:%d \"%s\" (0x%zx, 0x%zx) (tid=%u)\n",
>> + SanitizerToolName, StripModuleName(file), line, cond, (uptr)v1,
>> + (uptr)v2, tid);
>> + static atomic_uint32_t first_tid;
>> + u32 cmp = 0;
>> + if (!atomic_compare_exchange_strong(&first_tid, &cmp, tid,
>> + memory_order_relaxed)) {
>> + if (cmp == tid) {
>> + // Recursing into CheckFailed.
>> + } else {
>> + // Another thread fails already, let it print the stack and terminate.
>> + SleepForSeconds(2);
>> + }
>> Trap();
>> }
>> -
>> - if (CheckFailedCallback) {
>> - CheckFailedCallback(file, line, cond, v1, v2);
>> - }
>> - Report("Sanitizer CHECK failed: %s:%d %s (%lld, %lld)\n", file, line, cond,
>> - v1, v2);
>> + if (CheckUnwindCallback)
>> + CheckUnwindCallback();
>> Die();
>> }
>>
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_thread_registry.cpp b/libsanitizer/sanitizer_common/sanitizer_thread_registry.cpp
>> index f2c6f279931..3273da38bfd 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_thread_registry.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_thread_registry.cpp
>> @@ -85,7 +85,7 @@ void ThreadContextBase::SetCreated(uptr _user_id, u64 _unique_id,
>> unique_id = _unique_id;
>> detached = _detached;
>> // Parent tid makes no sense for the main thread.
>> - if (tid != 0)
>> + if (tid != kMainTid)
>> parent_tid = _parent_tid;
>> OnCreated(arg);
>> }
>> @@ -99,8 +99,6 @@ void ThreadContextBase::Reset() {
>>
>> // ThreadRegistry implementation.
>>
>> -const u32 ThreadRegistry::kUnknownTid = ~0U;
>> -
>> ThreadRegistry::ThreadRegistry(ThreadContextFactory factory, u32 max_threads,
>> u32 thread_quarantine_size, u32 max_reuse)
>> : context_factory_(factory),
>> @@ -135,7 +133,7 @@ uptr ThreadRegistry::GetMaxAliveThreads() {
>> u32 ThreadRegistry::CreateThread(uptr user_id, bool detached, u32 parent_tid,
>> void *arg) {
>> BlockingMutexLock l(&mtx_);
>> - u32 tid = kUnknownTid;
>> + u32 tid = kInvalidTid;
>> ThreadContextBase *tctx = QuarantinePop();
>> if (tctx) {
>> tid = tctx->tid;
>> @@ -155,7 +153,7 @@ u32 ThreadRegistry::CreateThread(uptr user_id, bool detached, u32 parent_tid,
>> Die();
>> }
>> CHECK_NE(tctx, 0);
>> - CHECK_NE(tid, kUnknownTid);
>> + CHECK_NE(tid, kInvalidTid);
>> CHECK_LT(tid, max_threads_);
>> CHECK_EQ(tctx->status, ThreadStatusInvalid);
>> alive_threads_++;
>> @@ -186,7 +184,7 @@ u32 ThreadRegistry::FindThread(FindThreadCallback cb, void *arg) {
>> if (tctx != 0 && cb(tctx, arg))
>> return tctx->tid;
>> }
>> - return kUnknownTid;
>> + return kInvalidTid;
>> }
>>
>> ThreadContextBase *
>> @@ -278,7 +276,7 @@ void ThreadRegistry::JoinThread(u32 tid, void *arg) {
>> // really started. We just did CreateThread for a prospective new
>> // thread before trying to create it, and then failed to actually
>> // create it, and so never called StartThread.
>> -void ThreadRegistry::FinishThread(u32 tid) {
>> +ThreadStatus ThreadRegistry::FinishThread(u32 tid) {
>> BlockingMutexLock l(&mtx_);
>> CHECK_GT(alive_threads_, 0);
>> alive_threads_--;
>> @@ -286,6 +284,7 @@ void ThreadRegistry::FinishThread(u32 tid) {
>> ThreadContextBase *tctx = threads_[tid];
>> CHECK_NE(tctx, 0);
>> bool dead = tctx->detached;
>> + ThreadStatus prev_status = tctx->status;
>> if (tctx->status == ThreadStatusRunning) {
>> CHECK_GT(running_threads_, 0);
>> running_threads_--;
>> @@ -300,6 +299,7 @@ void ThreadRegistry::FinishThread(u32 tid) {
>> QuarantinePush(tctx);
>> }
>> tctx->SetDestroyed();
>> + return prev_status;
>> }
>>
>> void ThreadRegistry::StartThread(u32 tid, tid_t os_id, ThreadType thread_type,
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_thread_registry.h b/libsanitizer/sanitizer_common/sanitizer_thread_registry.h
>> index 85c522a31ca..dcd445c28ae 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_thread_registry.h
>> +++ b/libsanitizer/sanitizer_common/sanitizer_thread_registry.h
>> @@ -87,8 +87,6 @@ typedef ThreadContextBase* (*ThreadContextFactory)(u32 tid);
>>
>> class ThreadRegistry {
>> public:
>> - static const u32 kUnknownTid;
>> -
>> ThreadRegistry(ThreadContextFactory factory, u32 max_threads,
>> u32 thread_quarantine_size, u32 max_reuse = 0);
>> void GetNumberOfThreads(uptr *total = nullptr, uptr *running = nullptr,
>> @@ -113,7 +111,7 @@ class ThreadRegistry {
>> void RunCallbackForEachThreadLocked(ThreadCallback cb, void *arg);
>>
>> typedef bool (*FindThreadCallback)(ThreadContextBase *tctx, void *arg);
>> - // Finds a thread using the provided callback. Returns kUnknownTid if no
>> + // Finds a thread using the provided callback. Returns kInvalidTid if no
>> // thread is found.
>> u32 FindThread(FindThreadCallback cb, void *arg);
>> // Should be guarded by ThreadRegistryLock. Return 0 if no thread
>> @@ -126,7 +124,8 @@ class ThreadRegistry {
>> void SetThreadNameByUserId(uptr user_id, const char *name);
>> void DetachThread(u32 tid, void *arg);
>> void JoinThread(u32 tid, void *arg);
>> - void FinishThread(u32 tid);
>> + // Finishes thread and returns previous status.
>> + ThreadStatus FinishThread(u32 tid);
>> void StartThread(u32 tid, tid_t os_id, ThreadType thread_type, void *arg);
>> void SetThreadUserId(u32 tid, uptr user_id);
>>
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.cpp b/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.cpp
>> index 10748f96420..1f664b6cf5b 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.cpp
>> @@ -12,6 +12,7 @@
>>
>> #include "sanitizer_tls_get_addr.h"
>>
>> +#include "sanitizer_atomic.h"
>> #include "sanitizer_flags.h"
>> #include "sanitizer_platform_interceptors.h"
>>
>> @@ -42,39 +43,54 @@ static atomic_uintptr_t number_of_live_dtls;
>>
>> static const uptr kDestroyedThread = -1;
>>
>> -static inline void DTLS_Deallocate(DTLS::DTV *dtv, uptr size) {
>> - if (!size) return;
>> - VReport(2, "__tls_get_addr: DTLS_Deallocate %p %zd\n", dtv, size);
>> - UnmapOrDie(dtv, size * sizeof(DTLS::DTV));
>> +static void DTLS_Deallocate(DTLS::DTVBlock *block) {
>> + VReport(2, "__tls_get_addr: DTLS_Deallocate %p %zd\n", block);
>> + UnmapOrDie(block, sizeof(DTLS::DTVBlock));
>> atomic_fetch_sub(&number_of_live_dtls, 1, memory_order_relaxed);
>> }
>>
>> -static inline void DTLS_Resize(uptr new_size) {
>> - if (dtls.dtv_size >= new_size) return;
>> - new_size = RoundUpToPowerOfTwo(new_size);
>> - new_size = Max(new_size, 4096UL / sizeof(DTLS::DTV));
>> - DTLS::DTV *new_dtv =
>> - (DTLS::DTV *)MmapOrDie(new_size * sizeof(DTLS::DTV), "DTLS_Resize");
>> +static DTLS::DTVBlock *DTLS_NextBlock(atomic_uintptr_t *cur) {
>> + uptr v = atomic_load(cur, memory_order_acquire);
>> + if (v == kDestroyedThread)
>> + return nullptr;
>> + DTLS::DTVBlock *next = (DTLS::DTVBlock *)v;
>> + if (next)
>> + return next;
>> + DTLS::DTVBlock *new_dtv =
>> + (DTLS::DTVBlock *)MmapOrDie(sizeof(DTLS::DTVBlock), "DTLS_NextBlock");
>> + uptr prev = 0;
>> + if (!atomic_compare_exchange_strong(cur, &prev, (uptr)new_dtv,
>> + memory_order_seq_cst)) {
>> + UnmapOrDie(new_dtv, sizeof(DTLS::DTVBlock));
>> + return (DTLS::DTVBlock *)prev;
>> + }
>> uptr num_live_dtls =
>> atomic_fetch_add(&number_of_live_dtls, 1, memory_order_relaxed);
>> - VReport(2, "__tls_get_addr: DTLS_Resize %p %zd\n", &dtls, num_live_dtls);
>> - CHECK_LT(num_live_dtls, 1 << 20);
>> - uptr old_dtv_size = dtls.dtv_size;
>> - DTLS::DTV *old_dtv = dtls.dtv;
>> - if (old_dtv_size)
>> - internal_memcpy(new_dtv, dtls.dtv, dtls.dtv_size * sizeof(DTLS::DTV));
>> - dtls.dtv = new_dtv;
>> - dtls.dtv_size = new_size;
>> - if (old_dtv_size)
>> - DTLS_Deallocate(old_dtv, old_dtv_size);
>> + VReport(2, "__tls_get_addr: DTLS_NextBlock %p %zd\n", &dtls, num_live_dtls);
>> + return new_dtv;
>> +}
>> +
>> +static DTLS::DTV *DTLS_Find(uptr id) {
>> + VReport(2, "__tls_get_addr: DTLS_Find %p %zd\n", &dtls, id);
>> + static constexpr uptr kPerBlock = ARRAY_SIZE(DTLS::DTVBlock::dtvs);
>> + DTLS::DTVBlock *cur = DTLS_NextBlock(&dtls.dtv_block);
>> + if (!cur)
>> + return nullptr;
>> + for (; id >= kPerBlock; id -= kPerBlock) cur = DTLS_NextBlock(&cur->next);
>> + return cur->dtvs + id;
>> }
>>
>> void DTLS_Destroy() {
>> if (!common_flags()->intercept_tls_get_addr) return;
>> - VReport(2, "__tls_get_addr: DTLS_Destroy %p %zd\n", &dtls, dtls.dtv_size);
>> - uptr s = dtls.dtv_size;
>> - dtls.dtv_size = kDestroyedThread; // Do this before unmap for AS-safety.
>> - DTLS_Deallocate(dtls.dtv, s);
>> + VReport(2, "__tls_get_addr: DTLS_Destroy %p\n", &dtls);
>> + DTLS::DTVBlock *block = (DTLS::DTVBlock *)atomic_exchange(
>> + &dtls.dtv_block, kDestroyedThread, memory_order_release);
>> + while (block) {
>> + DTLS::DTVBlock *next =
>> + (DTLS::DTVBlock *)atomic_load(&block->next, memory_order_acquire);
>> + DTLS_Deallocate(block);
>> + block = next;
>> + }
>> }
>>
>> #if defined(__powerpc64__) || defined(__mips__)
>> @@ -96,9 +112,9 @@ DTLS::DTV *DTLS_on_tls_get_addr(void *arg_void, void *res,
>> if (!common_flags()->intercept_tls_get_addr) return 0;
>> TlsGetAddrParam *arg = reinterpret_cast<TlsGetAddrParam *>(arg_void);
>> uptr dso_id = arg->dso_id;
>> - if (dtls.dtv_size == kDestroyedThread) return 0;
>> - DTLS_Resize(dso_id + 1);
>> - if (dtls.dtv[dso_id].beg) return 0;
>> + DTLS::DTV *dtv = DTLS_Find(dso_id);
>> + if (!dtv || dtv->beg)
>> + return 0;
>> uptr tls_size = 0;
>> uptr tls_beg = reinterpret_cast<uptr>(res) - arg->offset - kDtvOffset;
>> VReport(2, "__tls_get_addr: %p {%p,%p} => %p; tls_beg: %p; sp: %p "
>> @@ -126,9 +142,9 @@ DTLS::DTV *DTLS_on_tls_get_addr(void *arg_void, void *res,
>> // This may happen inside the DTOR of main thread, so just ignore it.
>> tls_size = 0;
>> }
>> - dtls.dtv[dso_id].beg = tls_beg;
>> - dtls.dtv[dso_id].size = tls_size;
>> - return dtls.dtv + dso_id;
>> + dtv->beg = tls_beg;
>> + dtv->size = tls_size;
>> + return dtv;
>> }
>>
>> void DTLS_on_libc_memalign(void *ptr, uptr size) {
>> @@ -141,7 +157,8 @@ void DTLS_on_libc_memalign(void *ptr, uptr size) {
>> DTLS *DTLS_Get() { return &dtls; }
>>
>> bool DTLSInDestruction(DTLS *dtls) {
>> - return dtls->dtv_size == kDestroyedThread;
>> + return atomic_load(&dtls->dtv_block, memory_order_relaxed) ==
>> + kDestroyedThread;
>> }
>>
>> #else
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.h b/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.h
>> index c7cd5a8bffc..a599c0bbc75 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.h
>> +++ b/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.h
>> @@ -28,6 +28,7 @@
>> #ifndef SANITIZER_TLS_GET_ADDR_H
>> #define SANITIZER_TLS_GET_ADDR_H
>>
>> +#include "sanitizer_atomic.h"
>> #include "sanitizer_common.h"
>>
>> namespace __sanitizer {
>> @@ -38,15 +39,31 @@ struct DTLS {
>> struct DTV {
>> uptr beg, size;
>> };
>> + struct DTVBlock {
>> + atomic_uintptr_t next;
>> + DTV dtvs[(4096UL - sizeof(next)) / sizeof(DTLS::DTV)];
>> + };
>> +
>> + static_assert(sizeof(DTVBlock) <= 4096UL, "Unexpected block size");
>>
>> - uptr dtv_size;
>> - DTV *dtv; // dtv_size elements, allocated by MmapOrDie.
>> + atomic_uintptr_t dtv_block;
>>
>> // Auxiliary fields, don't access them outside sanitizer_tls_get_addr.cpp
>> uptr last_memalign_size;
>> uptr last_memalign_ptr;
>> };
>>
>> +template <typename Fn>
>> +void ForEachDVT(DTLS *dtls, const Fn &fn) {
>> + DTLS::DTVBlock *block =
>> + (DTLS::DTVBlock *)atomic_load(&dtls->dtv_block, memory_order_acquire);
>> + while (block) {
>> + int id = 0;
>> + for (auto &d : block->dtvs) fn(d, id++);
>> + block = (DTLS::DTVBlock *)atomic_load(&block->next, memory_order_acquire);
>> + }
>> +}
>> +
>> // Returns pointer and size of a linker-allocated TLS block.
>> // Each block is returned exactly once.
>> DTLS::DTV *DTLS_on_tls_get_addr(void *arg, void *res, uptr static_tls_begin,
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_unwind_win.cpp b/libsanitizer/sanitizer_common/sanitizer_unwind_win.cpp
>> index e2edf428004..7e01c81d042 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_unwind_win.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_unwind_win.cpp
>> @@ -43,6 +43,10 @@ void BufferedStackTrace::UnwindSlow(uptr pc, u32 max_depth) {
>> trace_buffer[0] = pc;
>> }
>>
>> +#ifdef __clang__
>> +#pragma clang diagnostic push
>> +#pragma clang diagnostic ignored "-Wframe-larger-than="
>> +#endif
>> void BufferedStackTrace::UnwindSlow(uptr pc, void *context, u32 max_depth) {
>> CHECK(context);
>> CHECK_GE(max_depth, 2);
>> @@ -74,6 +78,9 @@ void BufferedStackTrace::UnwindSlow(uptr pc, void *context, u32 max_depth) {
>> trace_buffer[size++] = (uptr)stack_frame.AddrPC.Offset;
>> }
>> }
>> +#ifdef __clang__
>> +#pragma clang diagnostic pop
>> +#endif
>> #endif // #if !SANITIZER_GO
>>
>> #endif // SANITIZER_WINDOWS
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_win.cpp b/libsanitizer/sanitizer_common/sanitizer_win.cpp
>> index 85ac2633bde..f383e130fa5 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_win.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_win.cpp
>> @@ -334,8 +334,12 @@ bool MprotectNoAccess(uptr addr, uptr size) {
>> }
>>
>> void ReleaseMemoryPagesToOS(uptr beg, uptr end) {
>> - // This is almost useless on 32-bits.
>> - // FIXME: add madvise-analog when we move to 64-bits.
>> + uptr beg_aligned = RoundDownTo(beg, GetPageSizeCached()),
>> + end_aligned = RoundDownTo(end, GetPageSizeCached());
>> + CHECK(beg < end); // make sure the region is sane
>> + if (beg_aligned == end_aligned) // make sure we're freeing at least 1 page;
>> + return;
>> + UnmapOrDie((void *)beg, end_aligned - beg_aligned);
>> }
>>
>> void SetShadowRegionHugePageMode(uptr addr, uptr size) {
>> @@ -386,6 +390,12 @@ uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding,
>> return 0;
>> }
>>
>> +uptr MapDynamicShadowAndAliases(uptr shadow_size, uptr alias_size,
>> + uptr num_aliases, uptr ring_buffer_size) {
>> + CHECK(false && "HWASan aliasing is unimplemented on Windows");
>> + return 0;
>> +}
>> +
>> bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) {
>> MEMORY_BASIC_INFORMATION mbi;
>> CHECK(VirtualQuery((void *)range_start, &mbi, sizeof(mbi)));
>> @@ -564,7 +574,7 @@ void Abort() {
>> // load the image at this address. Therefore, we call it the preferred base. Any
>> // addresses in the DWARF typically assume that the object has been loaded at
>> // this address.
>> -static uptr GetPreferredBase(const char *modname) {
>> +static uptr GetPreferredBase(const char *modname, char *buf, size_t buf_size) {
>> fd_t fd = OpenFile(modname, RdOnly, nullptr);
>> if (fd == kInvalidFd)
>> return 0;
>> @@ -586,12 +596,10 @@ static uptr GetPreferredBase(const char *modname) {
>> // IMAGE_FILE_HEADER
>> // IMAGE_OPTIONAL_HEADER
>> // Seek to e_lfanew and read all that data.
>> - char buf[4 + sizeof(IMAGE_FILE_HEADER) + sizeof(IMAGE_OPTIONAL_HEADER)];
>> if (::SetFilePointer(fd, dos_header.e_lfanew, nullptr, FILE_BEGIN) ==
>> INVALID_SET_FILE_POINTER)
>> return 0;
>> - if (!ReadFromFile(fd, &buf[0], sizeof(buf), &bytes_read) ||
>> - bytes_read != sizeof(buf))
>> + if (!ReadFromFile(fd, buf, buf_size, &bytes_read) || bytes_read != buf_size)
>> return 0;
>>
>> // Check for "PE\0\0" before the PE header.
>> @@ -633,6 +641,10 @@ void ListOfModules::init() {
>> }
>> }
>>
>> + InternalMmapVector<char> buf(4 + sizeof(IMAGE_FILE_HEADER) +
>> + sizeof(IMAGE_OPTIONAL_HEADER));
>> + InternalMmapVector<wchar_t> modname_utf16(kMaxPathLength);
>> + InternalMmapVector<char> module_name(kMaxPathLength);
>> // |num_modules| is the number of modules actually present,
>> size_t num_modules = bytes_required / sizeof(HMODULE);
>> for (size_t i = 0; i < num_modules; ++i) {
>> @@ -642,15 +654,13 @@ void ListOfModules::init() {
>> continue;
>>
>> // Get the UTF-16 path and convert to UTF-8.
>> - wchar_t modname_utf16[kMaxPathLength];
>> int modname_utf16_len =
>> - GetModuleFileNameW(handle, modname_utf16, kMaxPathLength);
>> + GetModuleFileNameW(handle, &modname_utf16[0], kMaxPathLength);
>> if (modname_utf16_len == 0)
>> modname_utf16[0] = '\0';
>> - char module_name[kMaxPathLength];
>> - int module_name_len =
>> - ::WideCharToMultiByte(CP_UTF8, 0, modname_utf16, modname_utf16_len + 1,
>> - &module_name[0], kMaxPathLength, NULL, NULL);
>> + int module_name_len = ::WideCharToMultiByte(
>> + CP_UTF8, 0, &modname_utf16[0], modname_utf16_len + 1, &module_name[0],
>> + kMaxPathLength, NULL, NULL);
>> module_name[module_name_len] = '\0';
>>
>> uptr base_address = (uptr)mi.lpBaseOfDll;
>> @@ -660,15 +670,16 @@ void ListOfModules::init() {
>> // RVA when computing the module offset. This helps llvm-symbolizer find the
>> // right DWARF CU. In the common case that the image is loaded at it's
>> // preferred address, we will now print normal virtual addresses.
>> - uptr preferred_base = GetPreferredBase(&module_name[0]);
>> + uptr preferred_base =
>> + GetPreferredBase(&module_name[0], &buf[0], buf.size());
>> uptr adjusted_base = base_address - preferred_base;
>>
>> - LoadedModule cur_module;
>> - cur_module.set(module_name, adjusted_base);
>> + modules_.push_back(LoadedModule());
>> + LoadedModule &cur_module = modules_.back();
>> + cur_module.set(&module_name[0], adjusted_base);
>> // We add the whole module as one single address range.
>> cur_module.addAddressRange(base_address, end_address, /*executable*/ true,
>> /*writable*/ true);
>> - modules_.push_back(cur_module);
>> }
>> UnmapOrDie(hmodules, modules_buffer_size);
>> }
>> @@ -956,22 +967,27 @@ void SignalContext::InitPcSpBp() {
>>
>> uptr SignalContext::GetAddress() const {
>> EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD *)siginfo;
>> - return exception_record->ExceptionInformation[1];
>> + if (exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
>> + return exception_record->ExceptionInformation[1];
>> + return (uptr)exception_record->ExceptionAddress;
>> }
>>
>> bool SignalContext::IsMemoryAccess() const {
>> - return GetWriteFlag() != SignalContext::UNKNOWN;
>> + return ((EXCEPTION_RECORD *)siginfo)->ExceptionCode ==
>> + EXCEPTION_ACCESS_VIOLATION;
>> }
>>
>> -bool SignalContext::IsTrueFaultingAddress() const {
>> - // FIXME: Provide real implementation for this. See Linux and Mac variants.
>> - return IsMemoryAccess();
>> -}
>> +bool SignalContext::IsTrueFaultingAddress() const { return true; }
>>
>> SignalContext::WriteFlag SignalContext::GetWriteFlag() const {
>> EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD *)siginfo;
>> +
>> + // The write flag is only available for access violation exceptions.
>> + if (exception_record->ExceptionCode != EXCEPTION_ACCESS_VIOLATION)
>> + return SignalContext::UNKNOWN;
>> +
>> // The contents of this array are documented at
>> - // https://msdn.microsoft.com/en-us/library/windows/desktop/aa363082(v=vs.85).aspx
>> + // https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-exception_record
>> // The first element indicates read as 0, write as 1, or execute as 8. The
>> // second element is the faulting address.
>> switch (exception_record->ExceptionInformation[0]) {
>> @@ -1037,10 +1053,24 @@ const char *SignalContext::Describe() const {
>> }
>>
>> uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {
>> - // FIXME: Actually implement this function.
>> - CHECK_GT(buf_len, 0);
>> - buf[0] = 0;
>> - return 0;
>> + if (buf_len == 0)
>> + return 0;
>> +
>> + // Get the UTF-16 path and convert to UTF-8.
>> + InternalMmapVector<wchar_t> binname_utf16(kMaxPathLength);
>> + int binname_utf16_len =
>> + GetModuleFileNameW(NULL, &binname_utf16[0], kMaxPathLength);
>> + if (binname_utf16_len == 0) {
>> + buf[0] = '\0';
>> + return 0;
>> + }
>> + int binary_name_len =
>> + ::WideCharToMultiByte(CP_UTF8, 0, &binname_utf16[0], binname_utf16_len,
>> + buf, buf_len, NULL, NULL);
>> + if ((unsigned)binary_name_len == buf_len)
>> + --binary_name_len;
>> + buf[binary_name_len] = '\0';
>> + return binary_name_len;
>> }
>>
>> uptr ReadLongProcessName(/*out*/char *buf, uptr buf_len) {
>> diff --git a/libsanitizer/tsan/tsan_clock.cpp b/libsanitizer/tsan/tsan_clock.cpp
>> index c91b29cb22b..8e5188392ca 100644
>> --- a/libsanitizer/tsan/tsan_clock.cpp
>> +++ b/libsanitizer/tsan/tsan_clock.cpp
>> @@ -150,7 +150,7 @@ void ThreadClock::acquire(ClockCache *c, SyncClock *src) {
>> bool acquired = false;
>> for (unsigned i = 0; i < kDirtyTids; i++) {
>> SyncClock::Dirty dirty = src->dirty_[i];
>> - unsigned tid = dirty.tid;
>> + unsigned tid = dirty.tid();
>> if (tid != kInvalidTid) {
>> if (clk_[tid] < dirty.epoch) {
>> clk_[tid] = dirty.epoch;
>> @@ -299,10 +299,10 @@ void ThreadClock::ReleaseStore(ClockCache *c, SyncClock *dst) {
>> dst->tab_idx_ = cached_idx_;
>> dst->size_ = cached_size_;
>> dst->blocks_ = cached_blocks_;
>> - CHECK_EQ(dst->dirty_[0].tid, kInvalidTid);
>> + CHECK_EQ(dst->dirty_[0].tid(), kInvalidTid);
>> // The cached clock is shared (immutable),
>> // so this is where we store the current clock.
>> - dst->dirty_[0].tid = tid_;
>> + dst->dirty_[0].set_tid(tid_);
>> dst->dirty_[0].epoch = clk_[tid_];
>> dst->release_store_tid_ = tid_;
>> dst->release_store_reused_ = reused_;
>> @@ -336,8 +336,7 @@ void ThreadClock::ReleaseStore(ClockCache *c, SyncClock *dst) {
>> ce.reused = 0;
>> i++;
>> }
>> - for (uptr i = 0; i < kDirtyTids; i++)
>> - dst->dirty_[i].tid = kInvalidTid;
>> + for (uptr i = 0; i < kDirtyTids; i++) dst->dirty_[i].set_tid(kInvalidTid);
>> dst->release_store_tid_ = tid_;
>> dst->release_store_reused_ = reused_;
>> // Rememeber that we don't need to acquire it in future.
>> @@ -369,10 +368,10 @@ void ThreadClock::UpdateCurrentThread(ClockCache *c, SyncClock *dst) const {
>> // Update the threads time, but preserve 'acquired' flag.
>> for (unsigned i = 0; i < kDirtyTids; i++) {
>> SyncClock::Dirty *dirty = &dst->dirty_[i];
>> - const unsigned tid = dirty->tid;
>> + const unsigned tid = dirty->tid();
>> if (tid == tid_ || tid == kInvalidTid) {
>> CPP_STAT_INC(StatClockReleaseFast);
>> - dirty->tid = tid_;
>> + dirty->set_tid(tid_);
>> dirty->epoch = clk_[tid_];
>> return;
>> }
>> @@ -393,8 +392,8 @@ bool ThreadClock::IsAlreadyAcquired(const SyncClock *src) const {
>> return false;
>> for (unsigned i = 0; i < kDirtyTids; i++) {
>> SyncClock::Dirty dirty = src->dirty_[i];
>> - if (dirty.tid != kInvalidTid) {
>> - if (clk_[dirty.tid] < dirty.epoch)
>> + if (dirty.tid() != kInvalidTid) {
>> + if (clk_[dirty.tid()] < dirty.epoch)
>> return false;
>> }
>> }
>> @@ -453,8 +452,7 @@ void SyncClock::ResetImpl() {
>> blocks_ = 0;
>> release_store_tid_ = kInvalidTid;
>> release_store_reused_ = 0;
>> - for (uptr i = 0; i < kDirtyTids; i++)
>> - dirty_[i].tid = kInvalidTid;
>> + for (uptr i = 0; i < kDirtyTids; i++) dirty_[i].set_tid(kInvalidTid);
>> }
>>
>> void SyncClock::Resize(ClockCache *c, uptr nclk) {
>> @@ -503,10 +501,10 @@ void SyncClock::Resize(ClockCache *c, uptr nclk) {
>> void SyncClock::FlushDirty() {
>> for (unsigned i = 0; i < kDirtyTids; i++) {
>> Dirty *dirty = &dirty_[i];
>> - if (dirty->tid != kInvalidTid) {
>> - CHECK_LT(dirty->tid, size_);
>> - elem(dirty->tid).epoch = dirty->epoch;
>> - dirty->tid = kInvalidTid;
>> + if (dirty->tid() != kInvalidTid) {
>> + CHECK_LT(dirty->tid(), size_);
>> + elem(dirty->tid()).epoch = dirty->epoch;
>> + dirty->set_tid(kInvalidTid);
>> }
>> }
>> }
>> @@ -559,7 +557,7 @@ ALWAYS_INLINE bool SyncClock::Cachable() const {
>> if (size_ == 0)
>> return false;
>> for (unsigned i = 0; i < kDirtyTids; i++) {
>> - if (dirty_[i].tid != kInvalidTid)
>> + if (dirty_[i].tid() != kInvalidTid)
>> return false;
>> }
>> return atomic_load_relaxed(ref_ptr(tab_)) == 1;
>> @@ -606,7 +604,7 @@ ALWAYS_INLINE void SyncClock::append_block(u32 idx) {
>> u64 SyncClock::get(unsigned tid) const {
>> for (unsigned i = 0; i < kDirtyTids; i++) {
>> Dirty dirty = dirty_[i];
>> - if (dirty.tid == tid)
>> + if (dirty.tid() == tid)
>> return dirty.epoch;
>> }
>> return elem(tid).epoch;
>> @@ -625,9 +623,8 @@ void SyncClock::DebugDump(int(*printf)(const char *s, ...)) {
>> for (uptr i = 0; i < size_; i++)
>> printf("%s%llu", i == 0 ? "" : ",", elem(i).reused);
>> printf("] release_store_tid=%d/%d dirty_tids=%d[%llu]/%d[%llu]",
>> - release_store_tid_, release_store_reused_,
>> - dirty_[0].tid, dirty_[0].epoch,
>> - dirty_[1].tid, dirty_[1].epoch);
>> + release_store_tid_, release_store_reused_, dirty_[0].tid(),
>> + dirty_[0].epoch, dirty_[1].tid(), dirty_[1].epoch);
>> }
>>
>> void SyncClock::Iter::Next() {
>> diff --git a/libsanitizer/tsan/tsan_clock.h b/libsanitizer/tsan/tsan_clock.h
>> index 736cdae06ba..31376a1bc9e 100644
>> --- a/libsanitizer/tsan/tsan_clock.h
>> +++ b/libsanitizer/tsan/tsan_clock.h
>> @@ -17,7 +17,7 @@
>>
>> namespace __tsan {
>>
>> -typedef DenseSlabAlloc<ClockBlock, 1<<16, 1<<10> ClockAlloc;
>> +typedef DenseSlabAlloc<ClockBlock, 1 << 22, 1 << 10> ClockAlloc;
>> typedef DenseSlabAllocCache ClockCache;
>>
>> // The clock that lives in sync variables (mutexes, atomics, etc).
>> @@ -65,10 +65,20 @@ class SyncClock {
>> static const uptr kDirtyTids = 2;
>>
>> struct Dirty {
>> - u64 epoch : kClkBits;
>> - u64 tid : 64 - kClkBits; // kInvalidId if not active
>> + u32 tid() const { return tid_ == kShortInvalidTid ? kInvalidTid : tid_; }
>> + void set_tid(u32 tid) {
>> + tid_ = tid == kInvalidTid ? kShortInvalidTid : tid;
>> + }
>> + u64 epoch : kClkBits;
>> +
>> + private:
>> + // Full kInvalidTid won't fit into Dirty::tid.
>> + static const u64 kShortInvalidTid = (1ull << (64 - kClkBits)) - 1;
>> + u64 tid_ : 64 - kClkBits; // kInvalidId if not active
>> };
>>
>> + static_assert(sizeof(Dirty) == 8, "Dirty is not 64bit");
>> +
>> unsigned release_store_tid_;
>> unsigned release_store_reused_;
>> Dirty dirty_[kDirtyTids];
>> diff --git a/libsanitizer/tsan/tsan_defs.h b/libsanitizer/tsan/tsan_defs.h
>> index 293d7deccc3..f53787aeba9 100644
>> --- a/libsanitizer/tsan/tsan_defs.h
>> +++ b/libsanitizer/tsan/tsan_defs.h
>> @@ -98,8 +98,6 @@ const bool kCollectHistory = false;
>> const bool kCollectHistory = true;
>> #endif
>>
>> -const u16 kInvalidTid = kMaxTid + 1;
>> -
>> // The following "build consistency" machinery ensures that all source files
>> // are built in the same configuration. Inconsistent builds lead to
>> // hard to debug crashes.
>> diff --git a/libsanitizer/tsan/tsan_dense_alloc.h b/libsanitizer/tsan/tsan_dense_alloc.h
>> index 64fc50e95c2..6c89e405980 100644
>> --- a/libsanitizer/tsan/tsan_dense_alloc.h
>> +++ b/libsanitizer/tsan/tsan_dense_alloc.h
>> @@ -29,28 +29,40 @@ class DenseSlabAllocCache {
>> typedef u32 IndexT;
>> uptr pos;
>> IndexT cache[kSize];
>> - template<typename T, uptr kL1Size, uptr kL2Size> friend class DenseSlabAlloc;
>> + template <typename, uptr, uptr, u64>
>> + friend class DenseSlabAlloc;
>> };
>>
>> -template<typename T, uptr kL1Size, uptr kL2Size>
>> +template <typename T, uptr kL1Size, uptr kL2Size, u64 kReserved = 0>
>> class DenseSlabAlloc {
>> public:
>> typedef DenseSlabAllocCache Cache;
>> typedef typename Cache::IndexT IndexT;
>>
>> - explicit DenseSlabAlloc(const char *name) {
>> - // Check that kL1Size and kL2Size are sane.
>> - CHECK_EQ(kL1Size & (kL1Size - 1), 0);
>> - CHECK_EQ(kL2Size & (kL2Size - 1), 0);
>> - CHECK_GE(1ull << (sizeof(IndexT) * 8), kL1Size * kL2Size);
>> - // Check that it makes sense to use the dense alloc.
>> - CHECK_GE(sizeof(T), sizeof(IndexT));
>> - internal_memset(map_, 0, sizeof(map_));
>> + static_assert((kL1Size & (kL1Size - 1)) == 0,
>> + "kL1Size must be a power-of-two");
>> + static_assert((kL2Size & (kL2Size - 1)) == 0,
>> + "kL2Size must be a power-of-two");
>> + static_assert((kL1Size * kL2Size) <= (1ull << (sizeof(IndexT) * 8)),
>> + "kL1Size/kL2Size are too large");
>> + static_assert(((kL1Size * kL2Size - 1) & kReserved) == 0,
>> + "reserved bits don't fit");
>> + static_assert(sizeof(T) > sizeof(IndexT),
>> + "it doesn't make sense to use dense alloc");
>> +
>> + explicit DenseSlabAlloc(LinkerInitialized, const char *name) {
>> freelist_ = 0;
>> fillpos_ = 0;
>> name_ = name;
>> }
>>
>> + explicit DenseSlabAlloc(const char *name)
>> + : DenseSlabAlloc(LINKER_INITIALIZED, name) {
>> + // It can be very large.
>> + // Don't page it in for linker initialized objects.
>> + internal_memset(map_, 0, sizeof(map_));
>> + }
>> +
>> ~DenseSlabAlloc() {
>> for (uptr i = 0; i < kL1Size; i++) {
>> if (map_[i] != 0)
>> diff --git a/libsanitizer/tsan/tsan_external.cpp b/libsanitizer/tsan/tsan_external.cpp
>> index 466b2bf0f66..a87e12f2936 100644
>> --- a/libsanitizer/tsan/tsan_external.cpp
>> +++ b/libsanitizer/tsan/tsan_external.cpp
>> @@ -111,12 +111,12 @@ void __tsan_external_assign_tag(void *addr, void *tag) {
>>
>> SANITIZER_INTERFACE_ATTRIBUTE
>> void __tsan_external_read(void *addr, void *caller_pc, void *tag) {
>> - ExternalAccess(addr, STRIP_PC(caller_pc), tag, MemoryRead);
>> + ExternalAccess(addr, STRIP_PAC_PC(caller_pc), tag, MemoryRead);
>> }
>>
>> SANITIZER_INTERFACE_ATTRIBUTE
>> void __tsan_external_write(void *addr, void *caller_pc, void *tag) {
>> - ExternalAccess(addr, STRIP_PC(caller_pc), tag, MemoryWrite);
>> + ExternalAccess(addr, STRIP_PAC_PC(caller_pc), tag, MemoryWrite);
>> }
>> } // extern "C"
>>
>> diff --git a/libsanitizer/tsan/tsan_interceptors_mac.cpp b/libsanitizer/tsan/tsan_interceptors_mac.cpp
>> index aa29536d861..ed10fccc980 100644
>> --- a/libsanitizer/tsan/tsan_interceptors_mac.cpp
>> +++ b/libsanitizer/tsan/tsan_interceptors_mac.cpp
>> @@ -438,6 +438,7 @@ struct fake_shared_weak_count {
>> virtual void on_zero_shared() = 0;
>> virtual void _unused_0x18() = 0;
>> virtual void on_zero_shared_weak() = 0;
>> + virtual ~fake_shared_weak_count() = 0; // suppress -Wnon-virtual-dtor
>> };
>> } // namespace
>>
>> diff --git a/libsanitizer/tsan/tsan_interceptors_posix.cpp b/libsanitizer/tsan/tsan_interceptors_posix.cpp
>> index aa04d8dfb67..2651e22c39f 100644
>> --- a/libsanitizer/tsan/tsan_interceptors_posix.cpp
>> +++ b/libsanitizer/tsan/tsan_interceptors_posix.cpp
>> @@ -54,10 +54,6 @@ using namespace __tsan;
>> #define vfork __vfork14
>> #endif
>>
>> -#if SANITIZER_ANDROID
>> -#define mallopt(a, b)
>> -#endif
>> -
>> #ifdef __mips__
>> const int kSigCount = 129;
>> #else
>> @@ -85,6 +81,8 @@ extern "C" int pthread_attr_init(void *attr);
>> extern "C" int pthread_attr_destroy(void *attr);
>> DECLARE_REAL(int, pthread_attr_getdetachstate, void *, void *)
>> extern "C" int pthread_attr_setstacksize(void *attr, uptr stacksize);
>> +extern "C" int pthread_atfork(void (*prepare)(void), void (*parent)(void),
>> + void (*child)(void));
>> extern "C" int pthread_key_create(unsigned *key, void (*destructor)(void* v));
>> extern "C" int pthread_setspecific(unsigned key, const void *v);
>> DECLARE_REAL(int, pthread_mutexattr_gettype, void *, void *)
>> @@ -97,7 +95,7 @@ extern "C" void _exit(int status);
>> extern "C" int fileno_unlocked(void *stream);
>> extern "C" int dirfd(void *dirp);
>> #endif
>> -#if !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_NETBSD
>> +#if SANITIZER_GLIBC
>> extern "C" int mallopt(int param, int value);
>> #endif
>> #if SANITIZER_NETBSD
>> @@ -659,8 +657,11 @@ TSAN_INTERCEPTOR(void*, malloc, uptr size) {
>> return p;
>> }
>>
>> +// In glibc<2.25, dynamic TLS blocks are allocated by __libc_memalign. Intercept
>> +// __libc_memalign so that (1) we can detect races (2) free will not be called
>> +// on libc internally allocated blocks.
>> TSAN_INTERCEPTOR(void*, __libc_memalign, uptr align, uptr sz) {
>> - SCOPED_TSAN_INTERCEPTOR(__libc_memalign, align, sz);
>> + SCOPED_INTERCEPTOR_RAW(__libc_memalign, align, sz);
>> return user_memalign(thr, pc, align, sz);
>> }
>>
>> @@ -773,6 +774,11 @@ static void *mmap_interceptor(ThreadState *thr, uptr pc, Mmap real_mmap,
>> if (!fix_mmap_addr(&addr, sz, flags)) return MAP_FAILED;
>> void *res = real_mmap(addr, sz, prot, flags, fd, off);
>> if (res != MAP_FAILED) {
>> + if (!IsAppMem((uptr)res) || !IsAppMem((uptr)res + sz - 1)) {
>> + Report("ThreadSanitizer: mmap at bad address: addr=%p size=%p res=%p\n",
>> + addr, (void*)sz, res);
>> + Die();
>> + }
>> if (fd > 0) FdAccess(thr, pc, fd);
>> MemoryRangeImitateWriteOrResetRange(thr, pc, (uptr)res, sz);
>> }
>> @@ -1122,27 +1128,37 @@ static void *init_cond(void *c, bool force = false) {
>> return (void*)cond;
>> }
>>
>> +namespace {
>> +
>> +template <class Fn>
>> struct CondMutexUnlockCtx {
>> ScopedInterceptor *si;
>> ThreadState *thr;
>> uptr pc;
>> void *m;
>> + void *c;
>> + const Fn &fn;
>> +
>> + int Cancel() const { return fn(); }
>> + void Unlock() const;
>> };
>>
>> -static void cond_mutex_unlock(CondMutexUnlockCtx *arg) {
>> +template <class Fn>
>> +void CondMutexUnlockCtx<Fn>::Unlock() const {
>> // pthread_cond_wait interceptor has enabled async signal delivery
>> // (see BlockingCall below). Disable async signals since we are running
>> // tsan code. Also ScopedInterceptor and BlockingCall destructors won't run
>> // since the thread is cancelled, so we have to manually execute them
>> // (the thread still can run some user code due to pthread_cleanup_push).
>> - ThreadSignalContext *ctx = SigCtx(arg->thr);
>> + ThreadSignalContext *ctx = SigCtx(thr);
>> CHECK_EQ(atomic_load(&ctx->in_blocking_func, memory_order_relaxed), 1);
>> atomic_store(&ctx->in_blocking_func, 0, memory_order_relaxed);
>> - MutexPostLock(arg->thr, arg->pc, (uptr)arg->m, MutexFlagDoPreLockOnPostLock);
>> + MutexPostLock(thr, pc, (uptr)m, MutexFlagDoPreLockOnPostLock);
>> // Undo BlockingCall ctor effects.
>> - arg->thr->ignore_interceptors--;
>> - arg->si->~ScopedInterceptor();
>> + thr->ignore_interceptors--;
>> + si->~ScopedInterceptor();
>> }
>> +} // namespace
>>
>> INTERCEPTOR(int, pthread_cond_init, void *c, void *a) {
>> void *cond = init_cond(c, true);
>> @@ -1151,20 +1167,24 @@ INTERCEPTOR(int, pthread_cond_init, void *c, void *a) {
>> return REAL(pthread_cond_init)(cond, a);
>> }
>>
>> -static int cond_wait(ThreadState *thr, uptr pc, ScopedInterceptor *si,
>> - int (*fn)(void *c, void *m, void *abstime), void *c,
>> - void *m, void *t) {
>> +template <class Fn>
>> +int cond_wait(ThreadState *thr, uptr pc, ScopedInterceptor *si, const Fn &fn,
>> + void *c, void *m) {
>> MemoryAccessRange(thr, pc, (uptr)c, sizeof(uptr), false);
>> MutexUnlock(thr, pc, (uptr)m);
>> - CondMutexUnlockCtx arg = {si, thr, pc, m};
>> int res = 0;
>> // This ensures that we handle mutex lock even in case of pthread_cancel.
>> // See test/tsan/cond_cancel.cpp.
>> {
>> // Enable signal delivery while the thread is blocked.
>> BlockingCall bc(thr);
>> + CondMutexUnlockCtx<Fn> arg = {si, thr, pc, m, c, fn};
>> res = call_pthread_cancel_with_cleanup(
>> - fn, c, m, t, (void (*)(void *arg))cond_mutex_unlock, &arg);
>> + [](void *arg) -> int {
>> + return ((const CondMutexUnlockCtx<Fn> *)arg)->Cancel();
>> + },
>> + [](void *arg) { ((const CondMutexUnlockCtx<Fn> *)arg)->Unlock(); },
>> + &arg);
>> }
>> if (res == errno_EOWNERDEAD) MutexRepair(thr, pc, (uptr)m);
>> MutexPostLock(thr, pc, (uptr)m, MutexFlagDoPreLockOnPostLock);
>> @@ -1174,25 +1194,46 @@ static int cond_wait(ThreadState *thr, uptr pc, ScopedInterceptor *si,
>> INTERCEPTOR(int, pthread_cond_wait, void *c, void *m) {
>> void *cond = init_cond(c);
>> SCOPED_TSAN_INTERCEPTOR(pthread_cond_wait, cond, m);
>> - return cond_wait(thr, pc, &si, (int (*)(void *c, void *m, void *abstime))REAL(
>> - pthread_cond_wait),
>> - cond, m, 0);
>> + return cond_wait(
>> + thr, pc, &si, [=]() { return REAL(pthread_cond_wait)(cond, m); }, cond,
>> + m);
>> }
>>
>> INTERCEPTOR(int, pthread_cond_timedwait, void *c, void *m, void *abstime) {
>> void *cond = init_cond(c);
>> SCOPED_TSAN_INTERCEPTOR(pthread_cond_timedwait, cond, m, abstime);
>> - return cond_wait(thr, pc, &si, REAL(pthread_cond_timedwait), cond, m,
>> - abstime);
>> + return cond_wait(
>> + thr, pc, &si,
>> + [=]() { return REAL(pthread_cond_timedwait)(cond, m, abstime); }, cond,
>> + m);
>> }
>>
>> +#if SANITIZER_LINUX
>> +INTERCEPTOR(int, pthread_cond_clockwait, void *c, void *m,
>> + __sanitizer_clockid_t clock, void *abstime) {
>> + void *cond = init_cond(c);
>> + SCOPED_TSAN_INTERCEPTOR(pthread_cond_clockwait, cond, m, clock, abstime);
>> + return cond_wait(
>> + thr, pc, &si,
>> + [=]() { return REAL(pthread_cond_clockwait)(cond, m, clock, abstime); },
>> + cond, m);
>> +}
>> +#define TSAN_MAYBE_PTHREAD_COND_CLOCKWAIT TSAN_INTERCEPT(pthread_cond_clockwait)
>> +#else
>> +#define TSAN_MAYBE_PTHREAD_COND_CLOCKWAIT
>> +#endif
>> +
>> #if SANITIZER_MAC
>> INTERCEPTOR(int, pthread_cond_timedwait_relative_np, void *c, void *m,
>> void *reltime) {
>> void *cond = init_cond(c);
>> SCOPED_TSAN_INTERCEPTOR(pthread_cond_timedwait_relative_np, cond, m, reltime);
>> - return cond_wait(thr, pc, &si, REAL(pthread_cond_timedwait_relative_np), cond,
>> - m, reltime);
>> + return cond_wait(
>> + thr, pc, &si,
>> + [=]() {
>> + return REAL(pthread_cond_timedwait_relative_np)(cond, m, reltime);
>> + },
>> + cond, m);
>> }
>> #endif
>>
>> @@ -1937,7 +1978,8 @@ static void CallUserSignalHandler(ThreadState *thr, bool sync, bool acquire,
>> // because in async signal processing case (when handler is called directly
>> // from rtl_generic_sighandler) we have not yet received the reraised
>> // signal; and it looks too fragile to intercept all ways to reraise a signal.
>> - if (flags()->report_bugs && !sync && sig != SIGTERM && errno != 99) {
>> + if (ShouldReport(thr, ReportTypeErrnoInSignal) && !sync && sig != SIGTERM &&
>> + errno != 99) {
>> VarSizeStackTrace stack;
>> // StackTrace::GetNestInstructionPc(pc) is used because return address is
>> // expected, OutputReport() will undo this.
>> @@ -2107,26 +2149,32 @@ TSAN_INTERCEPTOR(int, fork, int fake) {
>> if (in_symbolizer())
>> return REAL(fork)(fake);
>> SCOPED_INTERCEPTOR_RAW(fork, fake);
>> + return REAL(fork)(fake);
>> +}
>> +
>> +void atfork_prepare() {
>> + if (in_symbolizer())
>> + return;
>> + ThreadState *thr = cur_thread();
>> + const uptr pc = StackTrace::GetCurrentPc();
>> ForkBefore(thr, pc);
>> - int pid;
>> - {
>> - // On OS X, REAL(fork) can call intercepted functions (OSSpinLockLock), and
>> - // we'll assert in CheckNoLocks() unless we ignore interceptors.
>> - ScopedIgnoreInterceptors ignore;
>> - pid = REAL(fork)(fake);
>> - }
>> - if (pid == 0) {
>> - // child
>> - ForkChildAfter(thr, pc);
>> - FdOnFork(thr, pc);
>> - } else if (pid > 0) {
>> - // parent
>> - ForkParentAfter(thr, pc);
>> - } else {
>> - // error
>> - ForkParentAfter(thr, pc);
>> - }
>> - return pid;
>> +}
>> +
>> +void atfork_parent() {
>> + if (in_symbolizer())
>> + return;
>> + ThreadState *thr = cur_thread();
>> + const uptr pc = StackTrace::GetCurrentPc();
>> + ForkParentAfter(thr, pc);
>> +}
>> +
>> +void atfork_child() {
>> + if (in_symbolizer())
>> + return;
>> + ThreadState *thr = cur_thread();
>> + const uptr pc = StackTrace::GetCurrentPc();
>> + ForkChildAfter(thr, pc);
>> + FdOnFork(thr, pc);
>> }
>>
>> TSAN_INTERCEPTOR(int, vfork, int fake) {
>> @@ -2479,13 +2527,10 @@ static USED void syscall_fd_release(uptr pc, int fd) {
>> FdRelease(thr, pc, fd);
>> }
>>
>> -static void syscall_pre_fork(uptr pc) {
>> - TSAN_SYSCALL();
>> - ForkBefore(thr, pc);
>> -}
>> +static void syscall_pre_fork(uptr pc) { ForkBefore(cur_thread(), pc); }
>>
>> static void syscall_post_fork(uptr pc, int pid) {
>> - TSAN_SYSCALL();
>> + ThreadState *thr = cur_thread();
>> if (pid == 0) {
>> // child
>> ForkChildAfter(thr, pc);
>> @@ -2635,7 +2680,7 @@ void InitializeInterceptors() {
>> #endif
>>
>> // Instruct libc malloc to consume less memory.
>> -#if SANITIZER_LINUX
>> +#if SANITIZER_GLIBC
>> mallopt(1, 0); // M_MXFAST
>> mallopt(-3, 32*1024); // M_MMAP_THRESHOLD
>> #endif
>> @@ -2698,6 +2743,8 @@ void InitializeInterceptors() {
>> TSAN_INTERCEPT_VER(pthread_cond_timedwait, PTHREAD_ABI_BASE);
>> TSAN_INTERCEPT_VER(pthread_cond_destroy, PTHREAD_ABI_BASE);
>>
>> + TSAN_MAYBE_PTHREAD_COND_CLOCKWAIT;
>> +
>> TSAN_INTERCEPT(pthread_mutex_init);
>> TSAN_INTERCEPT(pthread_mutex_destroy);
>> TSAN_INTERCEPT(pthread_mutex_trylock);
>> @@ -2799,6 +2846,10 @@ void InitializeInterceptors() {
>> Printf("ThreadSanitizer: failed to setup atexit callback\n");
>> Die();
>> }
>> + if (pthread_atfork(atfork_prepare, atfork_parent, atfork_child)) {
>> + Printf("ThreadSanitizer: failed to setup atfork callbacks\n");
>> + Die();
>> + }
>>
>> #if !SANITIZER_MAC && !SANITIZER_NETBSD && !SANITIZER_FREEBSD
>> if (pthread_key_create(&interceptor_ctx()->finalize_key, &thread_finalize)) {
>> diff --git a/libsanitizer/tsan/tsan_interface.cpp b/libsanitizer/tsan/tsan_interface.cpp
>> index 55f1c9834f7..9bd0e8580b1 100644
>> --- a/libsanitizer/tsan/tsan_interface.cpp
>> +++ b/libsanitizer/tsan/tsan_interface.cpp
>> @@ -40,13 +40,13 @@ void __tsan_write16(void *addr) {
>> }
>>
>> void __tsan_read16_pc(void *addr, void *pc) {
>> - MemoryRead(cur_thread(), STRIP_PC(pc), (uptr)addr, kSizeLog8);
>> - MemoryRead(cur_thread(), STRIP_PC(pc), (uptr)addr + 8, kSizeLog8);
>> + MemoryRead(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, kSizeLog8);
>> + MemoryRead(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr + 8, kSizeLog8);
>> }
>>
>> void __tsan_write16_pc(void *addr, void *pc) {
>> - MemoryWrite(cur_thread(), STRIP_PC(pc), (uptr)addr, kSizeLog8);
>> - MemoryWrite(cur_thread(), STRIP_PC(pc), (uptr)addr + 8, kSizeLog8);
>> + MemoryWrite(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, kSizeLog8);
>> + MemoryWrite(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr + 8, kSizeLog8);
>> }
>>
>> // __tsan_unaligned_read/write calls are emitted by compiler.
>> diff --git a/libsanitizer/tsan/tsan_interface.h b/libsanitizer/tsan/tsan_interface.h
>> index 6d7286ca5b8..6e022b56850 100644
>> --- a/libsanitizer/tsan/tsan_interface.h
>> +++ b/libsanitizer/tsan/tsan_interface.h
>> @@ -204,7 +204,7 @@ __extension__ typedef __int128 a128;
>> #endif
>>
>> // Part of ABI, do not change.
>> -// https://github.com/llvm/llvm-project/blob/master/libcxx/include/atomic
>> +// https://github.com/llvm/llvm-project/blob/main/libcxx/include/atomic
>> typedef enum {
>> mo_relaxed,
>> mo_consume,
>> @@ -415,6 +415,13 @@ void __tsan_go_atomic32_compare_exchange(ThreadState *thr, uptr cpc, uptr pc,
>> SANITIZER_INTERFACE_ATTRIBUTE
>> void __tsan_go_atomic64_compare_exchange(ThreadState *thr, uptr cpc, uptr pc,
>> u8 *a);
>> +
>> +SANITIZER_INTERFACE_ATTRIBUTE
>> +void __tsan_on_initialize();
>> +
>> +SANITIZER_INTERFACE_ATTRIBUTE
>> +int __tsan_on_finalize(int failed);
>> +
>> } // extern "C"
>>
>> } // namespace __tsan
>> diff --git a/libsanitizer/tsan/tsan_interface_inl.h b/libsanitizer/tsan/tsan_interface_inl.h
>> index f5d743c1077..5e77d4d3d28 100644
>> --- a/libsanitizer/tsan/tsan_interface_inl.h
>> +++ b/libsanitizer/tsan/tsan_interface_inl.h
>> @@ -51,35 +51,35 @@ void __tsan_write8(void *addr) {
>> }
>>
>> void __tsan_read1_pc(void *addr, void *pc) {
>> - MemoryRead(cur_thread(), STRIP_PC(pc), (uptr)addr, kSizeLog1);
>> + MemoryRead(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, kSizeLog1);
>> }
>>
>> void __tsan_read2_pc(void *addr, void *pc) {
>> - MemoryRead(cur_thread(), STRIP_PC(pc), (uptr)addr, kSizeLog2);
>> + MemoryRead(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, kSizeLog2);
>> }
>>
>> void __tsan_read4_pc(void *addr, void *pc) {
>> - MemoryRead(cur_thread(), STRIP_PC(pc), (uptr)addr, kSizeLog4);
>> + MemoryRead(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, kSizeLog4);
>> }
>>
>> void __tsan_read8_pc(void *addr, void *pc) {
>> - MemoryRead(cur_thread(), STRIP_PC(pc), (uptr)addr, kSizeLog8);
>> + MemoryRead(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, kSizeLog8);
>> }
>>
>> void __tsan_write1_pc(void *addr, void *pc) {
>> - MemoryWrite(cur_thread(), STRIP_PC(pc), (uptr)addr, kSizeLog1);
>> + MemoryWrite(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, kSizeLog1);
>> }
>>
>> void __tsan_write2_pc(void *addr, void *pc) {
>> - MemoryWrite(cur_thread(), STRIP_PC(pc), (uptr)addr, kSizeLog2);
>> + MemoryWrite(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, kSizeLog2);
>> }
>>
>> void __tsan_write4_pc(void *addr, void *pc) {
>> - MemoryWrite(cur_thread(), STRIP_PC(pc), (uptr)addr, kSizeLog4);
>> + MemoryWrite(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, kSizeLog4);
>> }
>>
>> void __tsan_write8_pc(void *addr, void *pc) {
>> - MemoryWrite(cur_thread(), STRIP_PC(pc), (uptr)addr, kSizeLog8);
>> + MemoryWrite(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, kSizeLog8);
>> }
>>
>> void __tsan_vptr_update(void **vptr_p, void *new_val) {
>> @@ -101,7 +101,7 @@ void __tsan_vptr_read(void **vptr_p) {
>> }
>>
>> void __tsan_func_entry(void *pc) {
>> - FuncEntry(cur_thread(), STRIP_PC(pc));
>> + FuncEntry(cur_thread(), STRIP_PAC_PC(pc));
>> }
>>
>> void __tsan_func_exit() {
>> @@ -125,9 +125,9 @@ void __tsan_write_range(void *addr, uptr size) {
>> }
>>
>> void __tsan_read_range_pc(void *addr, uptr size, void *pc) {
>> - MemoryAccessRange(cur_thread(), STRIP_PC(pc), (uptr)addr, size, false);
>> + MemoryAccessRange(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, size, false);
>> }
>>
>> void __tsan_write_range_pc(void *addr, uptr size, void *pc) {
>> - MemoryAccessRange(cur_thread(), STRIP_PC(pc), (uptr)addr, size, true);
>> + MemoryAccessRange(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, size, true);
>> }
>> diff --git a/libsanitizer/tsan/tsan_mman.cpp b/libsanitizer/tsan/tsan_mman.cpp
>> index 743e67bf2f7..45a39f0f8ec 100644
>> --- a/libsanitizer/tsan/tsan_mman.cpp
>> +++ b/libsanitizer/tsan/tsan_mman.cpp
>> @@ -145,7 +145,7 @@ void AllocatorPrintStats() {
>>
>> static void SignalUnsafeCall(ThreadState *thr, uptr pc) {
>> if (atomic_load_relaxed(&thr->in_signal_handler) == 0 ||
>> - !flags()->report_signal_unsafe)
>> + !ShouldReport(thr, ReportTypeSignalUnsafe))
>> return;
>> VarSizeStackTrace stack;
>> ObtainCurrentStack(thr, pc, &stack);
>> diff --git a/libsanitizer/tsan/tsan_platform.h b/libsanitizer/tsan/tsan_platform.h
>> index 16169cab666..101522d8fa4 100644
>> --- a/libsanitizer/tsan/tsan_platform.h
>> +++ b/libsanitizer/tsan/tsan_platform.h
>> @@ -23,9 +23,21 @@
>>
>> namespace __tsan {
>>
>> +#if defined(__x86_64__)
>> +#define HAS_48_BIT_ADDRESS_SPACE 1
>> +#elif SANITIZER_IOSSIM // arm64 iOS simulators (order of #if matters)
>> +#define HAS_48_BIT_ADDRESS_SPACE 1
>> +#elif SANITIZER_IOS // arm64 iOS devices (order of #if matters)
>> +#define HAS_48_BIT_ADDRESS_SPACE 0
>> +#elif SANITIZER_MAC // arm64 macOS (order of #if matters)
>> +#define HAS_48_BIT_ADDRESS_SPACE 1
>> +#else
>> +#define HAS_48_BIT_ADDRESS_SPACE 0
>> +#endif
>> +
>> #if !SANITIZER_GO
>>
>> -#if defined(__x86_64__)
>> +#if HAS_48_BIT_ADDRESS_SPACE
>> /*
>> C/C++ on linux/x86_64 and freebsd/x86_64
>> 0000 0000 1000 - 0080 0000 0000: main binary and/or MAP_32BIT mappings (512GB)
>> @@ -93,7 +105,7 @@ fe00 0000 00 - ff00 0000 00: heap (4 GB)
>> ff00 0000 00 - ff80 0000 00: - (2 GB)
>> ff80 0000 00 - ffff ffff ff: modules and main thread stack (<2 GB)
>> */
>> -struct Mapping {
>> +struct Mapping40 {
>> static const uptr kMetaShadowBeg = 0x4000000000ull;
>> static const uptr kMetaShadowEnd = 0x5000000000ull;
>> static const uptr kTraceMemBeg = 0xb000000000ull;
>> @@ -114,6 +126,7 @@ struct Mapping {
>> };
>>
>> #define TSAN_MID_APP_RANGE 1
>> +#define TSAN_RUNTIME_VMA 1
>> #elif defined(__aarch64__) && defined(__APPLE__)
>> /*
>> C/C++ on Darwin/iOS/ARM64 (36-bit VMA, 64 GB VM)
>> @@ -146,7 +159,7 @@ struct Mapping {
>> static const uptr kVdsoBeg = 0x7000000000000000ull;
>> };
>>
>> -#elif defined(__aarch64__)
>> +#elif defined(__aarch64__) && !defined(__APPLE__)
>> // AArch64 supports multiple VMA which leads to multiple address transformation
>> // functions. To support these multiple VMAS transformations and mappings TSAN
>> // runtime for AArch64 uses an external memory read (vmaSize) to select which
>> @@ -354,7 +367,7 @@ struct Mapping47 {
>> #define TSAN_RUNTIME_VMA 1
>> #endif
>>
>> -#elif SANITIZER_GO && !SANITIZER_WINDOWS && defined(__x86_64__)
>> +#elif SANITIZER_GO && !SANITIZER_WINDOWS && HAS_48_BIT_ADDRESS_SPACE
>>
>> /* Go on linux, darwin and freebsd on x86_64
>> 0000 0000 1000 - 0000 1000 0000: executable
>> @@ -502,7 +515,7 @@ Go on linux/mips64 (47-bit VMA)
>> 6000 0000 0000 - 6200 0000 0000: traces
>> 6200 0000 0000 - 8000 0000 0000: -
>> */
>> -struct Mapping {
>> +struct Mapping47 {
>> static const uptr kMetaShadowBeg = 0x300000000000ull;
>> static const uptr kMetaShadowEnd = 0x400000000000ull;
>> static const uptr kTraceMemBeg = 0x600000000000ull;
>> @@ -512,6 +525,9 @@ struct Mapping {
>> static const uptr kAppMemBeg = 0x000000001000ull;
>> static const uptr kAppMemEnd = 0x00e000000000ull;
>> };
>> +
>> +#define TSAN_RUNTIME_VMA 1
>> +
>> #else
>> # error "Unknown platform"
>> #endif
>> @@ -592,6 +608,16 @@ uptr MappingArchImpl(void) {
>> }
>> DCHECK(0);
>> return 0;
>> +#elif defined(__mips64)
>> + switch (vmaSize) {
>> +#if !SANITIZER_GO
>> + case 40: return MappingImpl<Mapping40, Type>();
>> +#else
>> + case 47: return MappingImpl<Mapping47, Type>();
>> +#endif
>> + }
>> + DCHECK(0);
>> + return 0;
>> #else
>> return MappingImpl<Mapping, Type>();
>> #endif
>> @@ -749,6 +775,16 @@ bool IsAppMem(uptr mem) {
>> }
>> DCHECK(0);
>> return false;
>> +#elif defined(__mips64)
>> + switch (vmaSize) {
>> +#if !SANITIZER_GO
>> + case 40: return IsAppMemImpl<Mapping40>(mem);
>> +#else
>> + case 47: return IsAppMemImpl<Mapping47>(mem);
>> +#endif
>> + }
>> + DCHECK(0);
>> + return false;
>> #else
>> return IsAppMemImpl<Mapping>(mem);
>> #endif
>> @@ -780,6 +816,16 @@ bool IsShadowMem(uptr mem) {
>> }
>> DCHECK(0);
>> return false;
>> +#elif defined(__mips64)
>> + switch (vmaSize) {
>> +#if !SANITIZER_GO
>> + case 40: return IsShadowMemImpl<Mapping40>(mem);
>> +#else
>> + case 47: return IsShadowMemImpl<Mapping47>(mem);
>> +#endif
>> + }
>> + DCHECK(0);
>> + return false;
>> #else
>> return IsShadowMemImpl<Mapping>(mem);
>> #endif
>> @@ -811,6 +857,16 @@ bool IsMetaMem(uptr mem) {
>> }
>> DCHECK(0);
>> return false;
>> +#elif defined(__mips64)
>> + switch (vmaSize) {
>> +#if !SANITIZER_GO
>> + case 40: return IsMetaMemImpl<Mapping40>(mem);
>> +#else
>> + case 47: return IsMetaMemImpl<Mapping47>(mem);
>> +#endif
>> + }
>> + DCHECK(0);
>> + return false;
>> #else
>> return IsMetaMemImpl<Mapping>(mem);
>> #endif
>> @@ -852,6 +908,16 @@ uptr MemToShadow(uptr x) {
>> }
>> DCHECK(0);
>> return 0;
>> +#elif defined(__mips64)
>> + switch (vmaSize) {
>> +#if !SANITIZER_GO
>> + case 40: return MemToShadowImpl<Mapping40>(x);
>> +#else
>> + case 47: return MemToShadowImpl<Mapping47>(x);
>> +#endif
>> + }
>> + DCHECK(0);
>> + return 0;
>> #else
>> return MemToShadowImpl<Mapping>(x);
>> #endif
>> @@ -895,6 +961,16 @@ u32 *MemToMeta(uptr x) {
>> }
>> DCHECK(0);
>> return 0;
>> +#elif defined(__mips64)
>> + switch (vmaSize) {
>> +#if !SANITIZER_GO
>> + case 40: return MemToMetaImpl<Mapping40>(x);
>> +#else
>> + case 47: return MemToMetaImpl<Mapping47>(x);
>> +#endif
>> + }
>> + DCHECK(0);
>> + return 0;
>> #else
>> return MemToMetaImpl<Mapping>(x);
>> #endif
>> @@ -951,6 +1027,16 @@ uptr ShadowToMem(uptr s) {
>> }
>> DCHECK(0);
>> return 0;
>> +#elif defined(__mips64)
>> + switch (vmaSize) {
>> +#if !SANITIZER_GO
>> + case 40: return ShadowToMemImpl<Mapping40>(s);
>> +#else
>> + case 47: return ShadowToMemImpl<Mapping47>(s);
>> +#endif
>> + }
>> + DCHECK(0);
>> + return 0;
>> #else
>> return ShadowToMemImpl<Mapping>(s);
>> #endif
>> @@ -990,6 +1076,16 @@ uptr GetThreadTrace(int tid) {
>> }
>> DCHECK(0);
>> return 0;
>> +#elif defined(__mips64)
>> + switch (vmaSize) {
>> +#if !SANITIZER_GO
>> + case 40: return GetThreadTraceImpl<Mapping40>(tid);
>> +#else
>> + case 47: return GetThreadTraceImpl<Mapping47>(tid);
>> +#endif
>> + }
>> + DCHECK(0);
>> + return 0;
>> #else
>> return GetThreadTraceImpl<Mapping>(tid);
>> #endif
>> @@ -1024,6 +1120,16 @@ uptr GetThreadTraceHeader(int tid) {
>> }
>> DCHECK(0);
>> return 0;
>> +#elif defined(__mips64)
>> + switch (vmaSize) {
>> +#if !SANITIZER_GO
>> + case 40: return GetThreadTraceHeaderImpl<Mapping40>(tid);
>> +#else
>> + case 47: return GetThreadTraceHeaderImpl<Mapping47>(tid);
>> +#endif
>> + }
>> + DCHECK(0);
>> + return 0;
>> #else
>> return GetThreadTraceHeaderImpl<Mapping>(tid);
>> #endif
>> @@ -1040,9 +1146,8 @@ int ExtractRecvmsgFDs(void *msg, int *fds, int nfd);
>> uptr ExtractLongJmpSp(uptr *env);
>> void ImitateTlsWrite(ThreadState *thr, uptr tls_addr, uptr tls_size);
>>
>> -int call_pthread_cancel_with_cleanup(int(*fn)(void *c, void *m,
>> - void *abstime), void *c, void *m, void *abstime,
>> - void(*cleanup)(void *arg), void *arg);
>> +int call_pthread_cancel_with_cleanup(int (*fn)(void *arg),
>> + void (*cleanup)(void *arg), void *arg);
>>
>> void DestroyThreadState();
>> void PlatformCleanUpThreadState(ThreadState *thr);
>> diff --git a/libsanitizer/tsan/tsan_platform_linux.cpp b/libsanitizer/tsan/tsan_platform_linux.cpp
>> index d136dcb1cec..e5b6690edfd 100644
>> --- a/libsanitizer/tsan/tsan_platform_linux.cpp
>> +++ b/libsanitizer/tsan/tsan_platform_linux.cpp
>> @@ -250,6 +250,20 @@ void InitializePlatformEarly() {
>> Die();
>> }
>> # endif
>> +#elif defined(__mips64)
>> +# if !SANITIZER_GO
>> + if (vmaSize != 40) {
>> + Printf("FATAL: ThreadSanitizer: unsupported VMA range\n");
>> + Printf("FATAL: Found %zd - Supported 40\n", vmaSize);
>> + Die();
>> + }
>> +# else
>> + if (vmaSize != 47) {
>> + Printf("FATAL: ThreadSanitizer: unsupported VMA range\n");
>> + Printf("FATAL: Found %zd - Supported 47\n", vmaSize);
>> + Die();
>> + }
>> +# endif
>> #endif
>> #endif
>> }
>> @@ -443,14 +457,13 @@ void ImitateTlsWrite(ThreadState *thr, uptr tls_addr, uptr tls_size) {
>>
>> // Note: this function runs with async signals enabled,
>> // so it must not touch any tsan state.
>> -int call_pthread_cancel_with_cleanup(int(*fn)(void *c, void *m,
>> - void *abstime), void *c, void *m, void *abstime,
>> - void(*cleanup)(void *arg), void *arg) {
>> +int call_pthread_cancel_with_cleanup(int (*fn)(void *arg),
>> + void (*cleanup)(void *arg), void *arg) {
>> // pthread_cleanup_push/pop are hardcore macros mess.
>> // We can't intercept nor call them w/o including pthread.h.
>> int res;
>> pthread_cleanup_push(cleanup, arg);
>> - res = fn(c, m, abstime);
>> + res = fn(arg);
>> pthread_cleanup_pop(0);
>> return res;
>> }
>> @@ -484,7 +497,7 @@ ThreadState *cur_thread() {
>> dead_thread_state->fast_state.SetIgnoreBit();
>> dead_thread_state->ignore_interceptors = 1;
>> dead_thread_state->is_dead = true;
>> - *const_cast<int*>(&dead_thread_state->tid) = -1;
>> + *const_cast<u32*>(&dead_thread_state->tid) = -1;
>> CHECK_EQ(0, internal_mprotect(dead_thread_state, sizeof(ThreadState),
>> PROT_READ));
>> }
>> diff --git a/libsanitizer/tsan/tsan_platform_mac.cpp b/libsanitizer/tsan/tsan_platform_mac.cpp
>> index ec2c5fb1621..d9719a136b2 100644
>> --- a/libsanitizer/tsan/tsan_platform_mac.cpp
>> +++ b/libsanitizer/tsan/tsan_platform_mac.cpp
>> @@ -234,7 +234,7 @@ static void my_pthread_introspection_hook(unsigned int event, pthread_t thread,
>> #endif
>>
>> void InitializePlatformEarly() {
>> -#if !SANITIZER_GO && defined(__aarch64__)
>> +#if !SANITIZER_GO && !HAS_48_BIT_ADDRESS_SPACE
>> uptr max_vm = GetMaxUserVirtualAddress() + 1;
>> if (max_vm != Mapping::kHiAppMemEnd) {
>> Printf("ThreadSanitizer: unsupported vm address limit %p, expected %p.\n",
>> @@ -306,14 +306,13 @@ void ImitateTlsWrite(ThreadState *thr, uptr tls_addr, uptr tls_size) {
>> #if !SANITIZER_GO
>> // Note: this function runs with async signals enabled,
>> // so it must not touch any tsan state.
>> -int call_pthread_cancel_with_cleanup(int(*fn)(void *c, void *m,
>> - void *abstime), void *c, void *m, void *abstime,
>> - void(*cleanup)(void *arg), void *arg) {
>> +int call_pthread_cancel_with_cleanup(int (*fn)(void *arg),
>> + void (*cleanup)(void *arg), void *arg) {
>> // pthread_cleanup_push/pop are hardcore macros mess.
>> // We can't intercept nor call them w/o including pthread.h.
>> int res;
>> pthread_cleanup_push(cleanup, arg);
>> - res = fn(c, m, abstime);
>> + res = fn(arg);
>> pthread_cleanup_pop(0);
>> return res;
>> }
>> diff --git a/libsanitizer/tsan/tsan_platform_posix.cpp b/libsanitizer/tsan/tsan_platform_posix.cpp
>> index d56b6c3b9c5..73e1d4577c2 100644
>> --- a/libsanitizer/tsan/tsan_platform_posix.cpp
>> +++ b/libsanitizer/tsan/tsan_platform_posix.cpp
>> @@ -99,7 +99,7 @@ void CheckAndProtect() {
>> Die();
>> }
>>
>> -#if defined(__aarch64__) && defined(__APPLE__)
>> +#if defined(__aarch64__) && defined(__APPLE__) && !HAS_48_BIT_ADDRESS_SPACE
>> ProtectRange(HeapMemEnd(), ShadowBeg());
>> ProtectRange(ShadowEnd(), MetaShadowBeg());
>> ProtectRange(MetaShadowEnd(), TraceMemBeg());
>> diff --git a/libsanitizer/tsan/tsan_report.cpp b/libsanitizer/tsan/tsan_report.cpp
>> index 968c7b97553..8ef9f0cd4fe 100644
>> --- a/libsanitizer/tsan/tsan_report.cpp
>> +++ b/libsanitizer/tsan/tsan_report.cpp
>> @@ -69,7 +69,7 @@ ReportDesc::~ReportDesc() {
>>
>> const int kThreadBufSize = 32;
>> const char *thread_name(char *buf, int tid) {
>> - if (tid == 0)
>> + if (tid == kMainTid)
>> return "main thread";
>> internal_snprintf(buf, kThreadBufSize, "thread T%d", tid);
>> return buf;
>> @@ -127,7 +127,7 @@ void PrintStack(const ReportStack *ent) {
>> }
>> SymbolizedStack *frame = ent->frames;
>> for (int i = 0; frame && frame->info.address; frame = frame->next, i++) {
>> - InternalScopedString res(2 * GetPageSizeCached());
>> + InternalScopedString res;
>> RenderFrame(&res, common_flags()->stack_trace_format, i,
>> frame->info.address, &frame->info,
>> common_flags()->symbolize_vs_style,
>> @@ -250,7 +250,7 @@ static void PrintMutex(const ReportMutex *rm) {
>>
>> static void PrintThread(const ReportThread *rt) {
>> Decorator d;
>> - if (rt->id == 0) // Little sense in describing the main thread.
>> + if (rt->id == kMainTid) // Little sense in describing the main thread.
>> return;
>> Printf("%s", d.ThreadDescription());
>> Printf(" Thread T%d", rt->id);
>> @@ -394,7 +394,7 @@ void PrintReport(const ReportDesc *rep) {
>>
>> #else // #if !SANITIZER_GO
>>
>> -const int kMainThreadId = 1;
>> +const u32 kMainGoroutineId = 1;
>>
>> void PrintStack(const ReportStack *ent) {
>> if (ent == 0 || ent->frames == 0) {
>> @@ -415,7 +415,7 @@ static void PrintMop(const ReportMop *mop, bool first) {
>> Printf("%s at %p by ",
>> (first ? (mop->write ? "Write" : "Read")
>> : (mop->write ? "Previous write" : "Previous read")), mop->addr);
>> - if (mop->tid == kMainThreadId)
>> + if (mop->tid == kMainGoroutineId)
>> Printf("main goroutine:\n");
>> else
>> Printf("goroutine %d:\n", mop->tid);
>> @@ -428,7 +428,7 @@ static void PrintLocation(const ReportLocation *loc) {
>> Printf("\n");
>> Printf("Heap block of size %zu at %p allocated by ",
>> loc->heap_chunk_size, loc->heap_chunk_start);
>> - if (loc->tid == kMainThreadId)
>> + if (loc->tid == kMainGoroutineId)
>> Printf("main goroutine:\n");
>> else
>> Printf("goroutine %d:\n", loc->tid);
>> @@ -448,7 +448,7 @@ static void PrintLocation(const ReportLocation *loc) {
>> }
>>
>> static void PrintThread(const ReportThread *rt) {
>> - if (rt->id == kMainThreadId)
>> + if (rt->id == kMainGoroutineId)
>> return;
>> Printf("\n");
>> Printf("Goroutine %d (%s) created at:\n",
>> diff --git a/libsanitizer/tsan/tsan_rtl.cpp b/libsanitizer/tsan/tsan_rtl.cpp
>> index 3d721eb95a2..0efa99788ab 100644
>> --- a/libsanitizer/tsan/tsan_rtl.cpp
>> +++ b/libsanitizer/tsan/tsan_rtl.cpp
>> @@ -11,17 +11,19 @@
>> // Main file (entry points) for the TSan run-time.
>> //===----------------------------------------------------------------------===//
>>
>> +#include "tsan_rtl.h"
>> +
>> #include "sanitizer_common/sanitizer_atomic.h"
>> #include "sanitizer_common/sanitizer_common.h"
>> #include "sanitizer_common/sanitizer_file.h"
>> #include "sanitizer_common/sanitizer_libc.h"
>> -#include "sanitizer_common/sanitizer_stackdepot.h"
>> #include "sanitizer_common/sanitizer_placement_new.h"
>> +#include "sanitizer_common/sanitizer_stackdepot.h"
>> #include "sanitizer_common/sanitizer_symbolizer.h"
>> #include "tsan_defs.h"
>> -#include "tsan_platform.h"
>> -#include "tsan_rtl.h"
>> +#include "tsan_interface.h"
>> #include "tsan_mman.h"
>> +#include "tsan_platform.h"
>> #include "tsan_suppressions.h"
>> #include "tsan_symbolize.h"
>> #include "ubsan/ubsan_init.h"
>> @@ -56,12 +58,23 @@ Context *ctx;
>> bool OnFinalize(bool failed);
>> void OnInitialize();
>> #else
>> +#include <dlfcn.h>
>> SANITIZER_WEAK_CXX_DEFAULT_IMPL
>> bool OnFinalize(bool failed) {
>> +#if !SANITIZER_GO
>> + if (auto *ptr = dlsym(RTLD_DEFAULT, "__tsan_on_finalize"))
>> + return reinterpret_cast<decltype(&__tsan_on_finalize)>(ptr)(failed);
>> +#endif
>> return failed;
>> }
>> SANITIZER_WEAK_CXX_DEFAULT_IMPL
>> -void OnInitialize() {}
>> +void OnInitialize() {
>> +#if !SANITIZER_GO
>> + if (auto *ptr = dlsym(RTLD_DEFAULT, "__tsan_on_initialize")) {
>> + return reinterpret_cast<decltype(&__tsan_on_initialize)>(ptr)();
>> + }
>> +#endif
>> +}
>> #endif
>>
>> static char thread_registry_placeholder[sizeof(ThreadRegistry)];
>> @@ -77,12 +90,19 @@ static ThreadContextBase *CreateThreadContext(u32 tid) {
>> new((void*)hdr) Trace();
>> // We are going to use only a small part of the trace with the default
>> // value of history_size. However, the constructor writes to the whole trace.
>> - // Unmap the unused part.
>> + // Release the unused part.
>> uptr hdr_end = hdr + sizeof(Trace);
>> hdr_end -= sizeof(TraceHeader) * (kTraceParts - TraceParts());
>> hdr_end = RoundUp(hdr_end, GetPageSizeCached());
>> - if (hdr_end < hdr + sizeof(Trace))
>> - UnmapOrDie((void*)hdr_end, hdr + sizeof(Trace) - hdr_end);
>> + if (hdr_end < hdr + sizeof(Trace)) {
>> + ReleaseMemoryPagesToOS(hdr_end, hdr + sizeof(Trace));
>> + uptr unused = hdr + sizeof(Trace) - hdr_end;
>> + if (hdr_end != (uptr)MmapFixedNoAccess(hdr_end, unused)) {
>> + Report("ThreadSanitizer: failed to mprotect(%p, %p)\n",
>> + hdr_end, unused);
>> + CHECK("unable to mprotect" && 0);
>> + }
>> + }
>> void *mem = internal_alloc(MBlockThreadContex, sizeof(ThreadContext));
>> return new(mem) ThreadContext(tid);
>> }
>> @@ -94,42 +114,45 @@ static const u32 kThreadQuarantineSize = 64;
>> #endif
>>
>> Context::Context()
>> - : initialized()
>> - , report_mtx(MutexTypeReport, StatMtxReport)
>> - , nreported()
>> - , nmissed_expected()
>> - , thread_registry(new(thread_registry_placeholder) ThreadRegistry(
>> - CreateThreadContext, kMaxTid, kThreadQuarantineSize, kMaxTidReuse))
>> - , racy_mtx(MutexTypeRacy, StatMtxRacy)
>> - , racy_stacks()
>> - , racy_addresses()
>> - , fired_suppressions_mtx(MutexTypeFired, StatMtxFired)
>> - , clock_alloc("clock allocator") {
>> + : initialized(),
>> + report_mtx(MutexTypeReport, StatMtxReport),
>> + nreported(),
>> + nmissed_expected(),
>> + thread_registry(new (thread_registry_placeholder) ThreadRegistry(
>> + CreateThreadContext, kMaxTid, kThreadQuarantineSize, kMaxTidReuse)),
>> + racy_mtx(MutexTypeRacy, StatMtxRacy),
>> + racy_stacks(),
>> + racy_addresses(),
>> + fired_suppressions_mtx(MutexTypeFired, StatMtxFired),
>> + clock_alloc(LINKER_INITIALIZED, "clock allocator") {
>> fired_suppressions.reserve(8);
>> }
>>
>> // The objects are allocated in TLS, so one may rely on zero-initialization.
>> -ThreadState::ThreadState(Context *ctx, int tid, int unique_id, u64 epoch,
>> - unsigned reuse_count,
>> - uptr stk_addr, uptr stk_size,
>> +ThreadState::ThreadState(Context *ctx, u32 tid, int unique_id, u64 epoch,
>> + unsigned reuse_count, uptr stk_addr, uptr stk_size,
>> uptr tls_addr, uptr tls_size)
>> - : fast_state(tid, epoch)
>> - // Do not touch these, rely on zero initialization,
>> - // they may be accessed before the ctor.
>> - // , ignore_reads_and_writes()
>> - // , ignore_interceptors()
>> - , clock(tid, reuse_count)
>> + : fast_state(tid, epoch)
>> + // Do not touch these, rely on zero initialization,
>> + // they may be accessed before the ctor.
>> + // , ignore_reads_and_writes()
>> + // , ignore_interceptors()
>> + ,
>> + clock(tid, reuse_count)
>> #if !SANITIZER_GO
>> - , jmp_bufs()
>> + ,
>> + jmp_bufs()
>> #endif
>> - , tid(tid)
>> - , unique_id(unique_id)
>> - , stk_addr(stk_addr)
>> - , stk_size(stk_size)
>> - , tls_addr(tls_addr)
>> - , tls_size(tls_size)
>> + ,
>> + tid(tid),
>> + unique_id(unique_id),
>> + stk_addr(stk_addr),
>> + stk_size(stk_size),
>> + tls_addr(tls_addr),
>> + tls_size(tls_size)
>> #if !SANITIZER_GO
>> - , last_sleep_clock(tid)
>> + ,
>> + last_sleep_clock(tid)
>> #endif
>> {
>> }
>> @@ -160,12 +183,12 @@ static void *BackgroundThread(void *arg) {
>> } else if (internal_strcmp(flags()->profile_memory, "stderr") == 0) {
>> mprof_fd = 2;
>> } else {
>> - InternalScopedString filename(kMaxPathLength);
>> + InternalScopedString filename;
>> filename.append("%s.%d", flags()->profile_memory, (int)internal_getpid());
>> fd_t fd = OpenFile(filename.data(), WrOnly);
>> if (fd == kInvalidFd) {
>> Printf("ThreadSanitizer: failed to open memory profile file '%s'\n",
>> - &filename[0]);
>> + filename.data());
>> } else {
>> mprof_fd = fd;
>> }
>> @@ -351,6 +374,18 @@ static void TsanOnDeadlySignal(int signo, void *siginfo, void *context) {
>> }
>> #endif
>>
>> +void CheckUnwind() {
>> + // There is high probability that interceptors will check-fail as well,
>> + // on the other hand there is no sense in processing interceptors
>> + // since we are going to die soon.
>> + ScopedIgnoreInterceptors ignore;
>> +#if !SANITIZER_GO
>> + cur_thread()->ignore_sync++;
>> + cur_thread()->ignore_reads_and_writes++;
>> +#endif
>> + PrintCurrentStackSlow(StackTrace::GetCurrentPc());
>> +}
>> +
>> void Initialize(ThreadState *thr) {
>> // Thread safe because done before all threads exist.
>> static bool is_initialized = false;
>> @@ -361,7 +396,7 @@ void Initialize(ThreadState *thr) {
>> ScopedIgnoreInterceptors ignore;
>> SanitizerToolName = "ThreadSanitizer";
>> // Install tool-specific callbacks in sanitizer_common.
>> - SetCheckFailedCallback(TsanCheckFailed);
>> + SetCheckUnwindCallback(CheckUnwind);
>>
>> ctx = new(ctx_placeholder) Context;
>> const char *env_name = SANITIZER_GO ? "GORACE" : "TSAN_OPTIONS";
>> @@ -499,23 +534,27 @@ int Finalize(ThreadState *thr) {
>> void ForkBefore(ThreadState *thr, uptr pc) {
>> ctx->thread_registry->Lock();
>> ctx->report_mtx.Lock();
>> - // Ignore memory accesses in the pthread_atfork callbacks.
>> - // If any of them triggers a data race we will deadlock
>> - // on the report_mtx.
>> - // We could ignore interceptors and sync operations as well,
>> + // Suppress all reports in the pthread_atfork callbacks.
>> + // Reports will deadlock on the report_mtx.
>> + // We could ignore sync operations as well,
>> // but so far it's unclear if it will do more good or harm.
>> // Unnecessarily ignoring things can lead to false positives later.
>> - ThreadIgnoreBegin(thr, pc);
>> + thr->suppress_reports++;
>> + // On OS X, REAL(fork) can call intercepted functions (OSSpinLockLock), and
>> + // we'll assert in CheckNoLocks() unless we ignore interceptors.
>> + thr->ignore_interceptors++;
>> }
>>
>> void ForkParentAfter(ThreadState *thr, uptr pc) {
>> - ThreadIgnoreEnd(thr, pc); // Begin is in ForkBefore.
>> + thr->suppress_reports--; // Enabled in ForkBefore.
>> + thr->ignore_interceptors--;
>> ctx->report_mtx.Unlock();
>> ctx->thread_registry->Unlock();
>> }
>>
>> void ForkChildAfter(ThreadState *thr, uptr pc) {
>> - ThreadIgnoreEnd(thr, pc); // Begin is in ForkBefore.
>> + thr->suppress_reports--; // Enabled in ForkBefore.
>> + thr->ignore_interceptors--;
>> ctx->report_mtx.Unlock();
>> ctx->thread_registry->Unlock();
>>
>> diff --git a/libsanitizer/tsan/tsan_rtl.h b/libsanitizer/tsan/tsan_rtl.h
>> index 04d474e044e..3ae519d34da 100644
>> --- a/libsanitizer/tsan/tsan_rtl.h
>> +++ b/libsanitizer/tsan/tsan_rtl.h
>> @@ -84,9 +84,6 @@ typedef Allocator::AllocatorCache AllocatorCache;
>> Allocator *allocator();
>> #endif
>>
>> -void TsanCheckFailed(const char *file, int line, const char *cond,
>> - u64 v1, u64 v2);
>> -
>> const u64 kShadowRodata = (u64)-1; // .rodata shadow marker
>>
>> // FastState (from most significant bit):
>> @@ -406,7 +403,7 @@ struct ThreadState {
>> #if TSAN_COLLECT_STATS
>> u64 stat[StatCnt];
>> #endif
>> - const int tid;
>> + const u32 tid;
>> const int unique_id;
>> bool in_symbolizer;
>> bool in_ignored_lib;
>> @@ -447,9 +444,8 @@ struct ThreadState {
>>
>> const ReportDesc *current_report;
>>
>> - explicit ThreadState(Context *ctx, int tid, int unique_id, u64 epoch,
>> - unsigned reuse_count,
>> - uptr stk_addr, uptr stk_size,
>> + explicit ThreadState(Context *ctx, u32 tid, int unique_id, u64 epoch,
>> + unsigned reuse_count, uptr stk_addr, uptr stk_size,
>> uptr tls_addr, uptr tls_size);
>> };
>>
>> @@ -624,6 +620,7 @@ class ScopedReport : public ScopedReportBase {
>> ScopedErrorReportLock lock_;
>> };
>>
>> +bool ShouldReport(ThreadState *thr, ReportType typ);
>> ThreadContext *IsThreadStackOrTls(uptr addr, bool *is_stack);
>> void RestoreStack(int tid, const u64 epoch, VarSizeStackTrace *stk,
>> MutexSet *mset, uptr *tag = nullptr);
>> diff --git a/libsanitizer/tsan/tsan_rtl_mutex.cpp b/libsanitizer/tsan/tsan_rtl_mutex.cpp
>> index 27897f0592b..0a8f3aa3ddb 100644
>> --- a/libsanitizer/tsan/tsan_rtl_mutex.cpp
>> +++ b/libsanitizer/tsan/tsan_rtl_mutex.cpp
>> @@ -51,6 +51,8 @@ static void ReportMutexMisuse(ThreadState *thr, uptr pc, ReportType typ,
>> // or false positives (e.g. unlock in a different thread).
>> if (SANITIZER_GO)
>> return;
>> + if (!ShouldReport(thr, typ))
>> + return;
>> ThreadRegistryLock l(ctx->thread_registry);
>> ScopedReport rep(typ);
>> rep.AddMutex(mid);
>> @@ -96,9 +98,8 @@ void MutexDestroy(ThreadState *thr, uptr pc, uptr addr, u32 flagz) {
>> ctx->dd->MutexInit(&cb, &s->dd);
>> }
>> bool unlock_locked = false;
>> - if (flags()->report_destroy_locked
>> - && s->owner_tid != SyncVar::kInvalidTid
>> - && !s->IsFlagSet(MutexFlagBroken)) {
>> + if (flags()->report_destroy_locked && s->owner_tid != kInvalidTid &&
>> + !s->IsFlagSet(MutexFlagBroken)) {
>> s->SetFlags(MutexFlagBroken);
>> unlock_locked = true;
>> }
>> @@ -107,7 +108,7 @@ void MutexDestroy(ThreadState *thr, uptr pc, uptr addr, u32 flagz) {
>> if (!unlock_locked)
>> s->Reset(thr->proc()); // must not reset it before the report is printed
>> s->mtx.Unlock();
>> - if (unlock_locked) {
>> + if (unlock_locked && ShouldReport(thr, ReportTypeMutexDestroyLocked)) {
>> ThreadRegistryLock l(ctx->thread_registry);
>> ScopedReport rep(ReportTypeMutexDestroyLocked);
>> rep.AddMutex(mid);
>> @@ -169,7 +170,7 @@ void MutexPostLock(ThreadState *thr, uptr pc, uptr addr, u32 flagz, int rec) {
>> thr->fast_state.IncrementEpoch();
>> TraceAddEvent(thr, thr->fast_state, EventTypeLock, s->GetId());
>> bool report_double_lock = false;
>> - if (s->owner_tid == SyncVar::kInvalidTid) {
>> + if (s->owner_tid == kInvalidTid) {
>> CHECK_EQ(s->recursion, 0);
>> s->owner_tid = thr->tid;
>> s->last_lock = thr->fast_state.raw();
>> @@ -229,7 +230,7 @@ int MutexUnlock(ThreadState *thr, uptr pc, uptr addr, u32 flagz) {
>> s->recursion -= rec;
>> if (s->recursion == 0) {
>> StatInc(thr, StatMutexUnlock);
>> - s->owner_tid = SyncVar::kInvalidTid;
>> + s->owner_tid = kInvalidTid;
>> ReleaseStoreImpl(thr, pc, &s->clock);
>> } else {
>> StatInc(thr, StatMutexRecUnlock);
>> @@ -275,7 +276,7 @@ void MutexPostReadLock(ThreadState *thr, uptr pc, uptr addr, u32 flagz) {
>> thr->fast_state.IncrementEpoch();
>> TraceAddEvent(thr, thr->fast_state, EventTypeRLock, s->GetId());
>> bool report_bad_lock = false;
>> - if (s->owner_tid != SyncVar::kInvalidTid) {
>> + if (s->owner_tid != kInvalidTid) {
>> if (flags()->report_mutex_bugs && !s->IsFlagSet(MutexFlagBroken)) {
>> s->SetFlags(MutexFlagBroken);
>> report_bad_lock = true;
>> @@ -314,7 +315,7 @@ void MutexReadUnlock(ThreadState *thr, uptr pc, uptr addr) {
>> thr->fast_state.IncrementEpoch();
>> TraceAddEvent(thr, thr->fast_state, EventTypeRUnlock, s->GetId());
>> bool report_bad_unlock = false;
>> - if (s->owner_tid != SyncVar::kInvalidTid) {
>> + if (s->owner_tid != kInvalidTid) {
>> if (flags()->report_mutex_bugs && !s->IsFlagSet(MutexFlagBroken)) {
>> s->SetFlags(MutexFlagBroken);
>> report_bad_unlock = true;
>> @@ -344,7 +345,7 @@ void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr) {
>> SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true);
>> bool write = true;
>> bool report_bad_unlock = false;
>> - if (s->owner_tid == SyncVar::kInvalidTid) {
>> + if (s->owner_tid == kInvalidTid) {
>> // Seems to be read unlock.
>> write = false;
>> StatInc(thr, StatMutexReadUnlock);
>> @@ -359,7 +360,7 @@ void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr) {
>> s->recursion--;
>> if (s->recursion == 0) {
>> StatInc(thr, StatMutexUnlock);
>> - s->owner_tid = SyncVar::kInvalidTid;
>> + s->owner_tid = kInvalidTid;
>> ReleaseStoreImpl(thr, pc, &s->clock);
>> } else {
>> StatInc(thr, StatMutexRecUnlock);
>> @@ -387,7 +388,7 @@ void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr) {
>> void MutexRepair(ThreadState *thr, uptr pc, uptr addr) {
>> DPrintf("#%d: MutexRepair %zx\n", thr->tid, addr);
>> SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true);
>> - s->owner_tid = SyncVar::kInvalidTid;
>> + s->owner_tid = kInvalidTid;
>> s->recursion = 0;
>> s->mtx.Unlock();
>> }
>> @@ -534,7 +535,7 @@ void AcquireReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c) {
>> }
>>
>> void ReportDeadlock(ThreadState *thr, uptr pc, DDReport *r) {
>> - if (r == 0)
>> + if (r == 0 || !ShouldReport(thr, ReportTypeDeadlock))
>> return;
>> ThreadRegistryLock l(ctx->thread_registry);
>> ScopedReport rep(ReportTypeDeadlock);
>> diff --git a/libsanitizer/tsan/tsan_rtl_ppc64.S b/libsanitizer/tsan/tsan_rtl_ppc64.S
>> index 9e533a71a9c..8285e21aa1e 100644
>> --- a/libsanitizer/tsan/tsan_rtl_ppc64.S
>> +++ b/libsanitizer/tsan/tsan_rtl_ppc64.S
>> @@ -1,6 +1,5 @@
>> #include "tsan_ppc_regs.h"
>>
>> - .machine altivec
>> .section .text
>> .hidden __tsan_setjmp
>> .globl _setjmp
>> diff --git a/libsanitizer/tsan/tsan_rtl_report.cpp b/libsanitizer/tsan/tsan_rtl_report.cpp
>> index 208d0df44df..706794fdad1 100644
>> --- a/libsanitizer/tsan/tsan_rtl_report.cpp
>> +++ b/libsanitizer/tsan/tsan_rtl_report.cpp
>> @@ -31,23 +31,6 @@ using namespace __sanitizer;
>>
>> static ReportStack *SymbolizeStack(StackTrace trace);
>>
>> -void TsanCheckFailed(const char *file, int line, const char *cond,
>> - u64 v1, u64 v2) {
>> - // There is high probability that interceptors will check-fail as well,
>> - // on the other hand there is no sense in processing interceptors
>> - // since we are going to die soon.
>> - ScopedIgnoreInterceptors ignore;
>> -#if !SANITIZER_GO
>> - cur_thread()->ignore_sync++;
>> - cur_thread()->ignore_reads_and_writes++;
>> -#endif
>> - Printf("FATAL: ThreadSanitizer CHECK failed: "
>> - "%s:%d \"%s\" (0x%zx, 0x%zx)\n",
>> - file, line, cond, (uptr)v1, (uptr)v2);
>> - PrintCurrentStackSlow(StackTrace::GetCurrentPc());
>> - Die();
>> -}
>> -
>> // Can be overriden by an application/test to intercept reports.
>> #ifdef TSAN_EXTERNAL_HOOKS
>> bool OnReport(const ReportDesc *rep, bool suppressed);
>> @@ -142,6 +125,34 @@ static ReportStack *SymbolizeStack(StackTrace trace) {
>> return stack;
>> }
>>
>> +bool ShouldReport(ThreadState *thr, ReportType typ) {
>> + // We set thr->suppress_reports in the fork context.
>> + // Taking any locking in the fork context can lead to deadlocks.
>> + // If any locks are already taken, it's too late to do this check.
>> + CheckNoLocks(thr);
>> + // For the same reason check we didn't lock thread_registry yet.
>> + if (SANITIZER_DEBUG)
>> + ThreadRegistryLock l(ctx->thread_registry);
>> + if (!flags()->report_bugs || thr->suppress_reports)
>> + return false;
>> + switch (typ) {
>> + case ReportTypeSignalUnsafe:
>> + return flags()->report_signal_unsafe;
>> + case ReportTypeThreadLeak:
>> +#if !SANITIZER_GO
>> + // It's impossible to join phantom threads
>> + // in the child after fork.
>> + if (ctx->after_multithreaded_fork)
>> + return false;
>> +#endif
>> + return flags()->report_thread_leaks;
>> + case ReportTypeMutexDestroyLocked:
>> + return flags()->report_destroy_locked;
>> + default:
>> + return true;
>> + }
>> +}
>> +
>> ScopedReportBase::ScopedReportBase(ReportType typ, uptr tag) {
>> ctx->thread_registry->CheckLocked();
>> void *mem = internal_alloc(MBlockReport, sizeof(ReportDesc));
>> @@ -497,8 +508,10 @@ static bool HandleRacyAddress(ThreadState *thr, uptr addr_min, uptr addr_max) {
>> }
>>
>> bool OutputReport(ThreadState *thr, const ScopedReport &srep) {
>> - if (!flags()->report_bugs || thr->suppress_reports)
>> - return false;
>> + // These should have been checked in ShouldReport.
>> + // It's too late to check them here, we have already taken locks.
>> + CHECK(flags()->report_bugs);
>> + CHECK(!thr->suppress_reports);
>> atomic_store_relaxed(&ctx->last_symbolize_time_ns, NanoTime());
>> const ReportDesc *rep = srep.GetReport();
>> CHECK_EQ(thr->current_report, nullptr);
>> @@ -589,7 +602,7 @@ void ReportRace(ThreadState *thr) {
>> // at best it will cause deadlocks on internal mutexes.
>> ScopedIgnoreInterceptors ignore;
>>
>> - if (!flags()->report_bugs)
>> + if (!ShouldReport(thr, ReportTypeRace))
>> return;
>> if (!flags()->report_atomic_races && !RaceBetweenAtomicAndFree(thr))
>> return;
>> @@ -722,8 +735,7 @@ void PrintCurrentStack(ThreadState *thr, uptr pc) {
>> // However, this solution is not reliable enough, please see dvyukov's comment
>> // http://reviews.llvm.org/D19148#406208
>> // Also see PR27280 comment 2 and 3 for breaking examples and analysis.
>> -ALWAYS_INLINE
>> -void PrintCurrentStackSlow(uptr pc) {
>> +ALWAYS_INLINE USED void PrintCurrentStackSlow(uptr pc) {
>> #if !SANITIZER_GO
>> uptr bp = GET_CURRENT_FRAME();
>> BufferedStackTrace *ptrace =
>> diff --git a/libsanitizer/tsan/tsan_rtl_thread.cpp b/libsanitizer/tsan/tsan_rtl_thread.cpp
>> index d80146735ea..6d1ccd8c9c7 100644
>> --- a/libsanitizer/tsan/tsan_rtl_thread.cpp
>> +++ b/libsanitizer/tsan/tsan_rtl_thread.cpp
>> @@ -51,7 +51,7 @@ struct OnCreatedArgs {
>>
>> void ThreadContext::OnCreated(void *arg) {
>> thr = 0;
>> - if (tid == 0)
>> + if (tid == kMainTid)
>> return;
>> OnCreatedArgs *args = static_cast<OnCreatedArgs *>(arg);
>> if (!args->thr) // GCD workers don't have a parent thread.
>> @@ -179,7 +179,7 @@ static void MaybeReportThreadLeak(ThreadContextBase *tctx_base, void *arg) {
>>
>> #if !SANITIZER_GO
>> static void ReportIgnoresEnabled(ThreadContext *tctx, IgnoreSet *set) {
>> - if (tctx->tid == 0) {
>> + if (tctx->tid == kMainTid) {
>> Printf("ThreadSanitizer: main thread finished with ignores enabled\n");
>> } else {
>> Printf("ThreadSanitizer: thread T%d %s finished with ignores enabled,"
>> @@ -210,7 +210,7 @@ static void ThreadCheckIgnore(ThreadState *thr) {}
>> void ThreadFinalize(ThreadState *thr) {
>> ThreadCheckIgnore(thr);
>> #if !SANITIZER_GO
>> - if (!flags()->report_thread_leaks)
>> + if (!ShouldReport(thr, ReportTypeThreadLeak))
>> return;
>> ThreadRegistryLock l(ctx->thread_registry);
>> Vector<ThreadLeak> leaks;
>> @@ -250,9 +250,10 @@ void ThreadStart(ThreadState *thr, int tid, tid_t os_id,
>> uptr tls_size = 0;
>> #if !SANITIZER_GO
>> if (thread_type != ThreadType::Fiber)
>> - GetThreadStackAndTls(tid == 0, &stk_addr, &stk_size, &tls_addr, &tls_size);
>> + GetThreadStackAndTls(tid == kMainTid, &stk_addr, &stk_size, &tls_addr,
>> + &tls_size);
>>
>> - if (tid) {
>> + if (tid != kMainTid) {
>> if (stk_addr && stk_size)
>> MemoryRangeImitateWrite(thr, /*pc=*/ 1, stk_addr, stk_size);
>>
>> @@ -313,7 +314,7 @@ static bool ConsumeThreadByUid(ThreadContextBase *tctx, void *arg) {
>> int ThreadConsumeTid(ThreadState *thr, uptr pc, uptr uid) {
>> ConsumeThreadContext findCtx = {uid, nullptr};
>> ctx->thread_registry->FindThread(ConsumeThreadByUid, &findCtx);
>> - int tid = findCtx.tctx ? findCtx.tctx->tid : ThreadRegistry::kUnknownTid;
>> + int tid = findCtx.tctx ? findCtx.tctx->tid : kInvalidTid;
>> DPrintf("#%d: ThreadTid uid=%zu tid=%d\n", thr->tid, uid, tid);
>> return tid;
>> }
>> diff --git a/libsanitizer/tsan/tsan_sync.cpp b/libsanitizer/tsan/tsan_sync.cpp
>> index 17ddd50f128..ba24f98ae9f 100644
>> --- a/libsanitizer/tsan/tsan_sync.cpp
>> +++ b/libsanitizer/tsan/tsan_sync.cpp
>> @@ -53,8 +53,8 @@ void SyncVar::Reset(Processor *proc) {
>> }
>>
>> MetaMap::MetaMap()
>> - : block_alloc_("heap block allocator")
>> - , sync_alloc_("sync allocator") {
>> + : block_alloc_(LINKER_INITIALIZED, "heap block allocator"),
>> + sync_alloc_(LINKER_INITIALIZED, "sync allocator") {
>> atomic_store(&uid_gen_, 0, memory_order_relaxed);
>> }
>>
>> diff --git a/libsanitizer/tsan/tsan_sync.h b/libsanitizer/tsan/tsan_sync.h
>> index 47f2739d8de..c4056f684d7 100644
>> --- a/libsanitizer/tsan/tsan_sync.h
>> +++ b/libsanitizer/tsan/tsan_sync.h
>> @@ -50,13 +50,11 @@ enum MutexFlags {
>> struct SyncVar {
>> SyncVar();
>>
>> - static const int kInvalidTid = -1;
>> -
>> uptr addr; // overwritten by DenseSlabAlloc freelist
>> Mutex mtx;
>> u64 uid; // Globally unique id.
>> u32 creation_stack_id;
>> - int owner_tid; // Set only by exclusive owners.
>> + u32 owner_tid; // Set only by exclusive owners.
>> u64 last_lock;
>> int recursion;
>> atomic_uint32_t flags;
>> @@ -130,8 +128,8 @@ class MetaMap {
>> static const u32 kFlagMask = 3u << 30;
>> static const u32 kFlagBlock = 1u << 30;
>> static const u32 kFlagSync = 2u << 30;
>> - typedef DenseSlabAlloc<MBlock, 1<<16, 1<<12> BlockAlloc;
>> - typedef DenseSlabAlloc<SyncVar, 1<<16, 1<<10> SyncAlloc;
>> + typedef DenseSlabAlloc<MBlock, 1 << 18, 1 << 12, kFlagMask> BlockAlloc;
>> + typedef DenseSlabAlloc<SyncVar, 1 << 20, 1 << 10, kFlagMask> SyncAlloc;
>> BlockAlloc block_alloc_;
>> SyncAlloc sync_alloc_;
>> atomic_uint64_t uid_gen_;
>> diff --git a/libsanitizer/ubsan/ubsan_diag.cpp b/libsanitizer/ubsan/ubsan_diag.cpp
>> index 1b2828d236d..ef2e495cac8 100644
>> --- a/libsanitizer/ubsan/ubsan_diag.cpp
>> +++ b/libsanitizer/ubsan/ubsan_diag.cpp
>> @@ -278,7 +278,7 @@ static void PrintMemorySnippet(const Decorator &Decor, MemoryLocation Loc,
>> }
>>
>> // Emit data.
>> - InternalScopedString Buffer(1024);
>> + InternalScopedString Buffer;
>> for (uptr P = Min; P != Max; ++P) {
>> unsigned char C = *reinterpret_cast<const unsigned char*>(P);
>> Buffer.append("%s%02x", (P % 8 == 0) ? " " : " ", C);
>> @@ -346,7 +346,7 @@ Diag::~Diag() {
>> // All diagnostics should be printed under report mutex.
>> ScopedReport::CheckLocked();
>> Decorator Decor;
>> - InternalScopedString Buffer(1024);
>> + InternalScopedString Buffer;
>>
>> // Prepare a report that a monitor process can inspect.
>> if (Level == DL_Error) {
>> @@ -388,6 +388,10 @@ ScopedReport::ScopedReport(ReportOptions Opts, Location SummaryLoc,
>> ScopedReport::~ScopedReport() {
>> MaybePrintStackTrace(Opts.pc, Opts.bp);
>> MaybeReportErrorSummary(SummaryLoc, Type);
>> +
>> + if (common_flags()->print_module_map >= 2)
>> + DumpProcessMap();
>> +
>> if (flags()->halt_on_error)
>> Die();
>> }
>> diff --git a/libsanitizer/ubsan/ubsan_flags.cpp b/libsanitizer/ubsan/ubsan_flags.cpp
>> index 9a66bd37518..25cefd46ce2 100644
>> --- a/libsanitizer/ubsan/ubsan_flags.cpp
>> +++ b/libsanitizer/ubsan/ubsan_flags.cpp
>> @@ -50,7 +50,6 @@ void InitializeFlags() {
>> {
>> CommonFlags cf;
>> cf.CopyFrom(*common_flags());
>> - cf.print_summary = false;
>> cf.external_symbolizer_path = GetFlag("UBSAN_SYMBOLIZER_PATH");
>> OverrideCommonFlags(cf);
>> }
>> diff --git a/libsanitizer/ubsan/ubsan_handlers.cpp b/libsanitizer/ubsan/ubsan_handlers.cpp
>> index 2184625aa6e..e201e6bba22 100644
>> --- a/libsanitizer/ubsan/ubsan_handlers.cpp
>> +++ b/libsanitizer/ubsan/ubsan_handlers.cpp
>> @@ -894,21 +894,6 @@ void __ubsan_handle_cfi_bad_type(CFICheckFailData *Data, ValueHandle Vtable,
>>
>> } // namespace __ubsan
>>
>> -void __ubsan::__ubsan_handle_cfi_bad_icall(CFIBadIcallData *CallData,
>> - ValueHandle Function) {
>> - GET_REPORT_OPTIONS(false);
>> - CFICheckFailData Data = {CFITCK_ICall, CallData->Loc, CallData->Type};
>> - handleCFIBadIcall(&Data, Function, Opts);
>> -}
>> -
>> -void __ubsan::__ubsan_handle_cfi_bad_icall_abort(CFIBadIcallData *CallData,
>> - ValueHandle Function) {
>> - GET_REPORT_OPTIONS(true);
>> - CFICheckFailData Data = {CFITCK_ICall, CallData->Loc, CallData->Type};
>> - handleCFIBadIcall(&Data, Function, Opts);
>> - Die();
>> -}
>> -
>> void __ubsan::__ubsan_handle_cfi_check_fail(CFICheckFailData *Data,
>> ValueHandle Value,
>> uptr ValidVtable) {
>> diff --git a/libsanitizer/ubsan/ubsan_handlers.h b/libsanitizer/ubsan/ubsan_handlers.h
>> index 9f412353fc0..219fb15de55 100644
>> --- a/libsanitizer/ubsan/ubsan_handlers.h
>> +++ b/libsanitizer/ubsan/ubsan_handlers.h
>> @@ -215,20 +215,12 @@ enum CFITypeCheckKind : unsigned char {
>> CFITCK_VMFCall,
>> };
>>
>> -struct CFIBadIcallData {
>> - SourceLocation Loc;
>> - const TypeDescriptor &Type;
>> -};
>> -
>> struct CFICheckFailData {
>> CFITypeCheckKind CheckKind;
>> SourceLocation Loc;
>> const TypeDescriptor &Type;
>> };
>>
>> -/// \brief Handle control flow integrity failure for indirect function calls.
>> -RECOVERABLE(cfi_bad_icall, CFIBadIcallData *Data, ValueHandle Function)
>> -
>> /// \brief Handle control flow integrity failures.
>> RECOVERABLE(cfi_check_fail, CFICheckFailData *Data, ValueHandle Function,
>> uptr VtableIsValid)
>> diff --git a/libsanitizer/ubsan/ubsan_init.cpp b/libsanitizer/ubsan/ubsan_init.cpp
>> index e0be5a72ec4..9931d85bf40 100644
>> --- a/libsanitizer/ubsan/ubsan_init.cpp
>> +++ b/libsanitizer/ubsan/ubsan_init.cpp
>> @@ -33,6 +33,11 @@ static void CommonInit() {
>> InitializeSuppressions();
>> }
>>
>> +static void UbsanDie() {
>> + if (common_flags()->print_module_map >= 1)
>> + DumpProcessMap();
>> +}
>> +
>> static void CommonStandaloneInit() {
>> SanitizerToolName = GetSanititizerToolName();
>> CacheBinaryName();
>> @@ -42,6 +47,10 @@ static void CommonStandaloneInit() {
>> AndroidLogInit();
>> InitializeCoverage(common_flags()->coverage, common_flags()->coverage_dir);
>> CommonInit();
>> +
>> + // Only add die callback when running in standalone mode to avoid printing
>> + // the same information from multiple sanitizers' output
>> + AddDieCallback(UbsanDie);
>> Symbolizer::LateInitialize();
>> }
>>
>> diff --git a/libsanitizer/ubsan/ubsan_monitor.cpp b/libsanitizer/ubsan/ubsan_monitor.cpp
>> index d064e95f76f..69dd986f9bd 100644
>> --- a/libsanitizer/ubsan/ubsan_monitor.cpp
>> +++ b/libsanitizer/ubsan/ubsan_monitor.cpp
>> @@ -17,7 +17,7 @@ using namespace __ubsan;
>> UndefinedBehaviorReport::UndefinedBehaviorReport(const char *IssueKind,
>> Location &Loc,
>> InternalScopedString &Msg)
>> - : IssueKind(IssueKind), Loc(Loc), Buffer(Msg.length() + 1) {
>> + : IssueKind(IssueKind), Loc(Loc) {
>> // We have the common sanitizer reporting lock, so it's safe to register a
>> // new UB report.
>> RegisterUndefinedBehaviorReport(this);
>> @@ -52,9 +52,9 @@ void __ubsan::__ubsan_get_current_report_data(const char **OutIssueKind,
>>
>> // Ensure that the first character of the diagnostic text can't start with a
>> // lowercase letter.
>> - char FirstChar = Buf.data()[0];
>> + char FirstChar = *Buf.data();
>> if (FirstChar >= 'a' && FirstChar <= 'z')
>> - Buf.data()[0] = FirstChar - 'a' + 'A';
>> + *Buf.data() += 'A' - 'a';
>>
>> *OutIssueKind = CurrentUBR->IssueKind;
>> *OutMessage = Buf.data();
>> diff --git a/libsanitizer/ubsan/ubsan_platform.h b/libsanitizer/ubsan/ubsan_platform.h
>> index 98542fcea96..51e535d1e22 100644
>> --- a/libsanitizer/ubsan/ubsan_platform.h
>> +++ b/libsanitizer/ubsan/ubsan_platform.h
>> @@ -12,16 +12,14 @@
>> #ifndef UBSAN_PLATFORM_H
>> #define UBSAN_PLATFORM_H
>>
>> -#ifndef CAN_SANITIZE_UB
>> // Other platforms should be easy to add, and probably work as-is.
>> #if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || \
>> - defined(__NetBSD__) || \
>> + defined(__NetBSD__) || defined(__DragonFly__) || \
>> (defined(__sun__) && defined(__svr4__)) || \
>> defined(_WIN32) || defined(__Fuchsia__) || defined(__rtems__)
>> # define CAN_SANITIZE_UB 1
>> #else
>> # define CAN_SANITIZE_UB 0
>> #endif
>> -#endif //CAN_SANITIZE_UB
>>
>> #endif
>
>> --
>> 2.31.1
>>
>
>
> --
> BR,
> Hongtao
>
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH] libsanitizer: merge from master
2021-06-04 7:36 ` Martin Liška
@ 2021-06-04 7:53 ` Hongtao Liu
0 siblings, 0 replies; 17+ messages in thread
From: Hongtao Liu @ 2021-06-04 7:53 UTC (permalink / raw)
To: Martin Liška; +Cc: GCC Patches
On Fri, Jun 4, 2021 at 3:36 PM Martin Liška <mliska@suse.cz> wrote:
>
> On 6/4/21 9:32 AM, Hongtao Liu wrote:
> > Hi:
> > I'm currently working on support hwasan with Intel LAM, i found
>
> Nice!
>
> > there's gap between gcc libsanitizer and corresponding llvm
> > compiler-rt, so could you help to sync from llvm to gcc libsanitizer.
> > Or is there's any instructions i can follow to sync it myself?
>
> Yes, please follow instructions mentioned in here:
> libsanitizer/HOWTO_MERGE
>
Great, that's what i need, thanks.
> Martin
>
> >
> > On Thu, May 13, 2021 at 3:50 PM Martin Liška <mliska@suse.cz> wrote:
> >>
> >> I'm planning to do merge from master twice a year.
> >> This merge was tested on x86_64-linux-gnu and ppc64le-linux-gnu
> >> and survives regression tests.
> >>
> >> Pushed to master.
> >> Thanks,
> >> Martin
> >>
> >> Merged revision: f58e0513dd95944b81ce7a6e7b49ba656de7d75f
> >> ---
> >> libsanitizer/MERGE | 2 +-
> >> libsanitizer/asan/asan_allocator.cpp | 32 +-
> >> libsanitizer/asan/asan_descriptions.cpp | 19 +-
> >> libsanitizer/asan/asan_descriptions.h | 13 +-
> >> libsanitizer/asan/asan_errors.cpp | 7 +-
> >> libsanitizer/asan/asan_fake_stack.cpp | 2 +-
> >> libsanitizer/asan/asan_fuchsia.cpp | 2 +-
> >> libsanitizer/asan/asan_globals.cpp | 19 +
> >> libsanitizer/asan/asan_interceptors.cpp | 41 +-
> >> libsanitizer/asan/asan_interceptors.h | 21 +-
> >> libsanitizer/asan/asan_linux.cpp | 3 +-
> >> libsanitizer/asan/asan_mapping.h | 25 +-
> >> libsanitizer/asan/asan_new_delete.cpp | 2 +-
> >> libsanitizer/asan/asan_poisoning.cpp | 2 +-
> >> libsanitizer/asan/asan_posix.cpp | 2 +-
> >> libsanitizer/asan/asan_rtl.cpp | 20 +-
> >> libsanitizer/asan/asan_stack.h | 9 -
> >> libsanitizer/asan/asan_thread.cpp | 51 +-
> >> libsanitizer/asan/asan_thread.h | 6 +-
> >> libsanitizer/asan/asan_win.cpp | 2 +-
> >> libsanitizer/builtins/assembly.h | 98 +++-
> >> libsanitizer/hwasan/hwasan.cpp | 19 +-
> >> libsanitizer/hwasan/hwasan.h | 41 +-
> >> libsanitizer/hwasan/hwasan_allocator.cpp | 28 +-
> >> libsanitizer/hwasan/hwasan_allocator.h | 19 +-
> >> libsanitizer/hwasan/hwasan_checks.h | 5 +-
> >> libsanitizer/hwasan/hwasan_dynamic_shadow.cpp | 16 +-
> >> libsanitizer/hwasan/hwasan_flags.h | 2 +
> >> libsanitizer/hwasan/hwasan_flags.inc | 9 +
> >> libsanitizer/hwasan/hwasan_interceptors.cpp | 3 +-
> >> .../hwasan/hwasan_interceptors_vfork.S | 3 +
> >> .../hwasan/hwasan_interface_internal.h | 3 +
> >> libsanitizer/hwasan/hwasan_linux.cpp | 41 +-
> >> libsanitizer/hwasan/hwasan_mapping.h | 2 +
> >> libsanitizer/hwasan/hwasan_memintrinsics.cpp | 4 +-
> >> libsanitizer/hwasan/hwasan_new_delete.cpp | 39 ++
> >> libsanitizer/hwasan/hwasan_report.cpp | 26 +-
> >> libsanitizer/hwasan/hwasan_setjmp.S | 6 +
> >> .../hwasan/hwasan_tag_mismatch_aarch64.S | 6 +
> >> libsanitizer/hwasan/hwasan_thread.cpp | 15 +-
> >> libsanitizer/hwasan/hwasan_thread.h | 4 +-
> >> libsanitizer/hwasan/hwasan_thread_list.h | 90 ++--
> >> .../include/sanitizer/common_interface_defs.h | 3 +
> >> .../include/sanitizer/dfsan_interface.h | 16 +
> >> .../include/sanitizer/hwasan_interface.h | 3 +
> >> .../include/sanitizer/memprof_interface.h | 5 +
> >> .../include/sanitizer/tsan_interface.h | 17 +-
> >> .../include/sanitizer/tsan_interface_atomic.h | 2 +-
> >> .../interception/interception_linux.cpp | 6 +-
> >> .../interception/interception_linux.h | 6 +-
> >> .../interception/interception_win.cpp | 6 +-
> >> libsanitizer/lsan/lsan_allocator.cpp | 26 +-
> >> libsanitizer/lsan/lsan_allocator.h | 2 +-
> >> libsanitizer/lsan/lsan_common.cpp | 234 ++++++---
> >> libsanitizer/lsan/lsan_common.h | 9 +-
> >> libsanitizer/lsan/lsan_common_fuchsia.cpp | 4 +-
> >> libsanitizer/lsan/lsan_fuchsia.h | 2 +-
> >> libsanitizer/lsan/lsan_interceptors.cpp | 2 +-
> >> libsanitizer/lsan/lsan_posix.cpp | 6 +-
> >> libsanitizer/lsan/lsan_thread.cpp | 2 +-
> >> .../sanitizer_allocator_combined.h | 4 +-
> >> .../sanitizer_allocator_primary32.h | 3 +-
> >> .../sanitizer_allocator_primary64.h | 93 +++-
> >> .../sanitizer_allocator_size_class_map.h | 2 +-
> >> .../sanitizer_atomic_clang_mips.h | 8 +-
> >> .../sanitizer_chained_origin_depot.cpp | 108 +++++
> >> .../sanitizer_chained_origin_depot.h | 88 ++++
> >> .../sanitizer_common/sanitizer_common.cpp | 10 +-
> >> .../sanitizer_common/sanitizer_common.h | 82 +++-
> >> .../sanitizer_common_interceptors.inc | 19 +-
> >> .../sanitizer_common_interceptors_ioctl.inc | 6 +-
> >> ...er_common_interceptors_vfork_aarch64.inc.S | 5 +
> >> .../sanitizer_common_interface.inc | 1 +
> >> .../sanitizer_common_libcdep.cpp | 7 +-
> >> .../sanitizer_common/sanitizer_file.cpp | 13 +
> >> .../sanitizer_common/sanitizer_file.h | 1 +
> >> .../sanitizer_common/sanitizer_flags.cpp | 7 +
> >> .../sanitizer_common/sanitizer_flags.inc | 2 +
> >> .../sanitizer_common/sanitizer_fuchsia.cpp | 72 +--
> >> .../sanitizer_interface_internal.h | 4 +
> >> .../sanitizer_internal_defs.h | 3 +
> >> .../sanitizer_common/sanitizer_libignore.cpp | 2 +-
> >> .../sanitizer_common/sanitizer_linux.cpp | 72 +--
> >> .../sanitizer_common/sanitizer_linux.h | 3 +-
> >> .../sanitizer_linux_libcdep.cpp | 447 ++++++++++--------
> >> .../sanitizer_local_address_space_view.h | 2 +-
> >> .../sanitizer_common/sanitizer_mac.cpp | 141 +++++-
> >> libsanitizer/sanitizer_common/sanitizer_mac.h | 37 --
> >> .../sanitizer_common/sanitizer_malloc_mac.inc | 6 +-
> >> .../sanitizer_common/sanitizer_netbsd.cpp | 6 +
> >> .../sanitizer_common/sanitizer_platform.h | 27 +-
> >> .../sanitizer_platform_interceptors.h | 113 +++--
> >> .../sanitizer_platform_limits_freebsd.cpp | 3 +
> >> .../sanitizer_platform_limits_linux.cpp | 7 +-
> >> .../sanitizer_platform_limits_posix.cpp | 85 ++--
> >> .../sanitizer_platform_limits_posix.h | 4 +-
> >> .../sanitizer_common/sanitizer_posix.cpp | 4 +-
> >> .../sanitizer_common/sanitizer_posix.h | 4 +
> >> .../sanitizer_posix_libcdep.cpp | 2 +-
> >> .../sanitizer_common/sanitizer_printf.cpp | 57 ++-
> >> .../sanitizer_procmaps_common.cpp | 2 +-
> >> .../sanitizer_procmaps_mac.cpp | 4 +-
> >> .../sanitizer_procmaps_solaris.cpp | 4 +-
> >> .../sanitizer_common/sanitizer_ptrauth.h | 20 +-
> >> .../sanitizer_common/sanitizer_stackdepot.cpp | 3 +-
> >> .../sanitizer_common/sanitizer_stacktrace.cpp | 20 +-
> >> .../sanitizer_common/sanitizer_stacktrace.h | 2 -
> >> .../sanitizer_stacktrace_libcdep.cpp | 8 +-
> >> .../sanitizer_stoptheworld_linux_libcdep.cpp | 5 +
> >> .../sanitizer_suppressions.cpp | 4 +-
> >> .../sanitizer_symbolizer_libcdep.cpp | 2 +-
> >> .../sanitizer_symbolizer_markup.cpp | 4 +
> >> .../sanitizer_symbolizer_posix_libcdep.cpp | 11 +-
> >> .../sanitizer_symbolizer_report.cpp | 6 +-
> >> .../sanitizer_symbolizer_win.cpp | 18 +-
> >> .../sanitizer_termination.cpp | 33 +-
> >> .../sanitizer_thread_registry.cpp | 14 +-
> >> .../sanitizer_thread_registry.h | 7 +-
> >> .../sanitizer_tls_get_addr.cpp | 79 ++--
> >> .../sanitizer_common/sanitizer_tls_get_addr.h | 21 +-
> >> .../sanitizer_common/sanitizer_unwind_win.cpp | 7 +
> >> .../sanitizer_common/sanitizer_win.cpp | 84 ++--
> >> libsanitizer/tsan/tsan_clock.cpp | 37 +-
> >> libsanitizer/tsan/tsan_clock.h | 16 +-
> >> libsanitizer/tsan/tsan_defs.h | 2 -
> >> libsanitizer/tsan/tsan_dense_alloc.h | 32 +-
> >> libsanitizer/tsan/tsan_external.cpp | 4 +-
> >> libsanitizer/tsan/tsan_interceptors_mac.cpp | 1 +
> >> libsanitizer/tsan/tsan_interceptors_posix.cpp | 149 ++++--
> >> libsanitizer/tsan/tsan_interface.cpp | 8 +-
> >> libsanitizer/tsan/tsan_interface.h | 9 +-
> >> libsanitizer/tsan/tsan_interface_inl.h | 22 +-
> >> libsanitizer/tsan/tsan_mman.cpp | 2 +-
> >> libsanitizer/tsan/tsan_platform.h | 121 ++++-
> >> libsanitizer/tsan/tsan_platform_linux.cpp | 23 +-
> >> libsanitizer/tsan/tsan_platform_mac.cpp | 9 +-
> >> libsanitizer/tsan/tsan_platform_posix.cpp | 2 +-
> >> libsanitizer/tsan/tsan_report.cpp | 14 +-
> >> libsanitizer/tsan/tsan_rtl.cpp | 129 +++--
> >> libsanitizer/tsan/tsan_rtl.h | 11 +-
> >> libsanitizer/tsan/tsan_rtl_mutex.cpp | 25 +-
> >> libsanitizer/tsan/tsan_rtl_ppc64.S | 1 -
> >> libsanitizer/tsan/tsan_rtl_report.cpp | 56 ++-
> >> libsanitizer/tsan/tsan_rtl_thread.cpp | 13 +-
> >> libsanitizer/tsan/tsan_sync.cpp | 4 +-
> >> libsanitizer/tsan/tsan_sync.h | 8 +-
> >> libsanitizer/ubsan/ubsan_diag.cpp | 8 +-
> >> libsanitizer/ubsan/ubsan_flags.cpp | 1 -
> >> libsanitizer/ubsan/ubsan_handlers.cpp | 15 -
> >> libsanitizer/ubsan/ubsan_handlers.h | 8 -
> >> libsanitizer/ubsan/ubsan_init.cpp | 9 +
> >> libsanitizer/ubsan/ubsan_monitor.cpp | 6 +-
> >> libsanitizer/ubsan/ubsan_platform.h | 4 +-
> >> 153 files changed, 2538 insertions(+), 1239 deletions(-)
> >> create mode 100644 libsanitizer/sanitizer_common/sanitizer_chained_origin_depot.cpp
> >> create mode 100644 libsanitizer/sanitizer_common/sanitizer_chained_origin_depot.h
> >>
> >> diff --git a/libsanitizer/MERGE b/libsanitizer/MERGE
> >> index 0fb64a9567c..c4731d0866c 100644
> >> --- a/libsanitizer/MERGE
> >> +++ b/libsanitizer/MERGE
> >> @@ -1,4 +1,4 @@
> >> -6e7dd1e3e1170080b76b5dcc5716bdd974343233
> >> +f58e0513dd95944b81ce7a6e7b49ba656de7d75f
> >>
> >> The first line of this file holds the git revision number of the
> >> last merge done from the master library sources.
> >> diff --git a/libsanitizer/asan/asan_allocator.cpp b/libsanitizer/asan/asan_allocator.cpp
> >> index 58b496a3ca4..7c8bb504332 100644
> >> --- a/libsanitizer/asan/asan_allocator.cpp
> >> +++ b/libsanitizer/asan/asan_allocator.cpp
> >> @@ -476,7 +476,7 @@ struct Allocator {
> >> return false;
> >> if (m->Beg() != addr) return false;
> >> AsanThread *t = GetCurrentThread();
> >> - m->SetAllocContext(t ? t->tid() : 0, StackDepotPut(*stack));
> >> + m->SetAllocContext(t ? t->tid() : kMainTid, StackDepotPut(*stack));
> >> return true;
> >> }
> >>
> >> @@ -570,7 +570,7 @@ struct Allocator {
> >> m->SetUsedSize(size);
> >> m->user_requested_alignment_log = user_requested_alignment_log;
> >>
> >> - m->SetAllocContext(t ? t->tid() : 0, StackDepotPut(*stack));
> >> + m->SetAllocContext(t ? t->tid() : kMainTid, StackDepotPut(*stack));
> >>
> >> uptr size_rounded_down_to_granularity =
> >> RoundDownTo(size, SHADOW_GRANULARITY);
> >> @@ -1183,6 +1183,34 @@ IgnoreObjectResult IgnoreObjectLocked(const void *p) {
> >> m->lsan_tag = __lsan::kIgnored;
> >> return kIgnoreObjectSuccess;
> >> }
> >> +
> >> +void GetAdditionalThreadContextPtrs(ThreadContextBase *tctx, void *ptrs) {
> >> + // Look for the arg pointer of threads that have been created or are running.
> >> + // This is necessary to prevent false positive leaks due to the AsanThread
> >> + // holding the only live reference to a heap object. This can happen because
> >> + // the `pthread_create()` interceptor doesn't wait for the child thread to
> >> + // start before returning and thus loosing the the only live reference to the
> >> + // heap object on the stack.
> >> +
> >> + __asan::AsanThreadContext *atctx =
> >> + reinterpret_cast<__asan::AsanThreadContext *>(tctx);
> >> + __asan::AsanThread *asan_thread = atctx->thread;
> >> +
> >> + // Note ThreadStatusRunning is required because there is a small window where
> >> + // the thread status switches to `ThreadStatusRunning` but the `arg` pointer
> >> + // still isn't on the stack yet.
> >> + if (atctx->status != ThreadStatusCreated &&
> >> + atctx->status != ThreadStatusRunning)
> >> + return;
> >> +
> >> + uptr thread_arg = reinterpret_cast<uptr>(asan_thread->get_arg());
> >> + if (!thread_arg)
> >> + return;
> >> +
> >> + auto ptrsVec = reinterpret_cast<InternalMmapVector<uptr> *>(ptrs);
> >> + ptrsVec->push_back(thread_arg);
> >> +}
> >> +
> >> } // namespace __lsan
> >>
> >> // ---------------------- Interface ---------------- {{{1
> >> diff --git a/libsanitizer/asan/asan_descriptions.cpp b/libsanitizer/asan/asan_descriptions.cpp
> >> index 153c874a4e7..2ba8a02f841 100644
> >> --- a/libsanitizer/asan/asan_descriptions.cpp
> >> +++ b/libsanitizer/asan/asan_descriptions.cpp
> >> @@ -44,11 +44,11 @@ void DescribeThread(AsanThreadContext *context) {
> >> CHECK(context);
> >> asanThreadRegistry().CheckLocked();
> >> // No need to announce the main thread.
> >> - if (context->tid == 0 || context->announced) {
> >> + if (context->tid == kMainTid || context->announced) {
> >> return;
> >> }
> >> context->announced = true;
> >> - InternalScopedString str(1024);
> >> + InternalScopedString str;
> >> str.append("Thread %s", AsanThreadIdAndName(context).c_str());
> >> if (context->parent_tid == kInvalidTid) {
> >> str.append(" created by unknown thread\n");
> >> @@ -77,7 +77,6 @@ static bool GetShadowKind(uptr addr, ShadowKind *shadow_kind) {
> >> } else if (AddrIsInLowShadow(addr)) {
> >> *shadow_kind = kShadowKindLow;
> >> } else {
> >> - CHECK(0 && "Address is not in memory and not in shadow?");
> >> return false;
> >> }
> >> return true;
> >> @@ -126,7 +125,7 @@ static void GetAccessToHeapChunkInformation(ChunkAccess *descr,
> >>
> >> static void PrintHeapChunkAccess(uptr addr, const ChunkAccess &descr) {
> >> Decorator d;
> >> - InternalScopedString str(4096);
> >> + InternalScopedString str;
> >> str.append("%s", d.Location());
> >> switch (descr.access_type) {
> >> case kAccessTypeLeft:
> >> @@ -243,7 +242,7 @@ static void PrintAccessAndVarIntersection(const StackVarDescr &var, uptr addr,
> >> else if (addr >= prev_var_end && addr - prev_var_end >= var.beg - addr_end)
> >> pos_descr = "underflows";
> >> }
> >> - InternalScopedString str(1024);
> >> + InternalScopedString str;
> >> str.append(" [%zd, %zd)", var.beg, var_end);
> >> // Render variable name.
> >> str.append(" '");
> >> @@ -276,7 +275,7 @@ bool DescribeAddressIfStack(uptr addr, uptr access_size) {
> >> // Global descriptions
> >> static void DescribeAddressRelativeToGlobal(uptr addr, uptr access_size,
> >> const __asan_global &g) {
> >> - InternalScopedString str(4096);
> >> + InternalScopedString str;
> >> Decorator d;
> >> str.append("%s", d.Location());
> >> if (addr < g.beg) {
> >> @@ -464,7 +463,13 @@ AddressDescription::AddressDescription(uptr addr, uptr access_size,
> >> return;
> >> }
> >> data.kind = kAddressKindWild;
> >> - addr = 0;
> >> + data.wild.addr = addr;
> >> + data.wild.access_size = access_size;
> >> +}
> >> +
> >> +void WildAddressDescription::Print() const {
> >> + Printf("Address %p is a wild pointer inside of access range of size %p.\n",
> >> + addr, access_size);
> >> }
> >>
> >> void PrintAddressDescription(uptr addr, uptr access_size,
> >> diff --git a/libsanitizer/asan/asan_descriptions.h b/libsanitizer/asan/asan_descriptions.h
> >> index ee0e2061559..650e2eb9173 100644
> >> --- a/libsanitizer/asan/asan_descriptions.h
> >> +++ b/libsanitizer/asan/asan_descriptions.h
> >> @@ -146,6 +146,13 @@ struct StackAddressDescription {
> >> bool GetStackAddressInformation(uptr addr, uptr access_size,
> >> StackAddressDescription *descr);
> >>
> >> +struct WildAddressDescription {
> >> + uptr addr;
> >> + uptr access_size;
> >> +
> >> + void Print() const;
> >> +};
> >> +
> >> struct GlobalAddressDescription {
> >> uptr addr;
> >> // Assume address is close to at most four globals.
> >> @@ -193,7 +200,7 @@ class AddressDescription {
> >> HeapAddressDescription heap;
> >> StackAddressDescription stack;
> >> GlobalAddressDescription global;
> >> - uptr addr;
> >> + WildAddressDescription wild;
> >> };
> >> };
> >>
> >> @@ -211,7 +218,7 @@ class AddressDescription {
> >> uptr Address() const {
> >> switch (data.kind) {
> >> case kAddressKindWild:
> >> - return data.addr;
> >> + return data.wild.addr;
> >> case kAddressKindShadow:
> >> return data.shadow.addr;
> >> case kAddressKindHeap:
> >> @@ -226,7 +233,7 @@ class AddressDescription {
> >> void Print(const char *bug_descr = nullptr) const {
> >> switch (data.kind) {
> >> case kAddressKindWild:
> >> - Printf("Address %p is a wild pointer.\n", data.addr);
> >> + data.wild.Print();
> >> return;
> >> case kAddressKindShadow:
> >> return data.shadow.Print();
> >> diff --git a/libsanitizer/asan/asan_errors.cpp b/libsanitizer/asan/asan_errors.cpp
> >> index 541c6e0353b..e68e6971f96 100644
> >> --- a/libsanitizer/asan/asan_errors.cpp
> >> +++ b/libsanitizer/asan/asan_errors.cpp
> >> @@ -343,7 +343,8 @@ void ErrorODRViolation::Print() {
> >> Report("ERROR: AddressSanitizer: %s (%p):\n", scariness.GetDescription(),
> >> global1.beg);
> >> Printf("%s", d.Default());
> >> - InternalScopedString g1_loc(256), g2_loc(256);
> >> + InternalScopedString g1_loc;
> >> + InternalScopedString g2_loc;
> >> PrintGlobalLocation(&g1_loc, global1);
> >> PrintGlobalLocation(&g2_loc, global2);
> >> Printf(" [1] size=%zd '%s' %s\n", global1.size,
> >> @@ -360,7 +361,7 @@ void ErrorODRViolation::Print() {
> >> Report(
> >> "HINT: if you don't care about these errors you may set "
> >> "ASAN_OPTIONS=detect_odr_violation=0\n");
> >> - InternalScopedString error_msg(256);
> >> + InternalScopedString error_msg;
> >> error_msg.append("%s: global '%s' at %s", scariness.GetDescription(),
> >> MaybeDemangleGlobalName(global1.name), g1_loc.data());
> >> ReportErrorSummary(error_msg.data());
> >> @@ -554,7 +555,7 @@ static void PrintShadowMemoryForAddress(uptr addr) {
> >> uptr shadow_addr = MemToShadow(addr);
> >> const uptr n_bytes_per_row = 16;
> >> uptr aligned_shadow = shadow_addr & ~(n_bytes_per_row - 1);
> >> - InternalScopedString str(4096 * 8);
> >> + InternalScopedString str;
> >> str.append("Shadow bytes around the buggy address:\n");
> >> for (int i = -5; i <= 5; i++) {
> >> uptr row_shadow_addr = aligned_shadow + i * n_bytes_per_row;
> >> diff --git a/libsanitizer/asan/asan_fake_stack.cpp b/libsanitizer/asan/asan_fake_stack.cpp
> >> index 295e6debc96..1f873fec7d7 100644
> >> --- a/libsanitizer/asan/asan_fake_stack.cpp
> >> +++ b/libsanitizer/asan/asan_fake_stack.cpp
> >> @@ -65,7 +65,7 @@ FakeStack *FakeStack::Create(uptr stack_size_log) {
> >> void FakeStack::Destroy(int tid) {
> >> PoisonAll(0);
> >> if (Verbosity() >= 2) {
> >> - InternalScopedString str(kNumberOfSizeClasses * 50);
> >> + InternalScopedString str;
> >> for (uptr class_id = 0; class_id < kNumberOfSizeClasses; class_id++)
> >> str.append("%zd: %zd/%zd; ", class_id, hint_position_[class_id],
> >> NumberOfFrames(stack_size_log(), class_id));
> >> diff --git a/libsanitizer/asan/asan_fuchsia.cpp b/libsanitizer/asan/asan_fuchsia.cpp
> >> index 6c61344f87c..b0c7255144a 100644
> >> --- a/libsanitizer/asan/asan_fuchsia.cpp
> >> +++ b/libsanitizer/asan/asan_fuchsia.cpp
> >> @@ -81,7 +81,7 @@ void AsanTSDInit(void (*destructor)(void *tsd)) {
> >> void PlatformTSDDtor(void *tsd) { UNREACHABLE(__func__); }
> >>
> >> static inline size_t AsanThreadMmapSize() {
> >> - return RoundUpTo(sizeof(AsanThread), PAGE_SIZE);
> >> + return RoundUpTo(sizeof(AsanThread), _zx_system_get_page_size());
> >> }
> >>
> >> struct AsanThread::InitOptions {
> >> diff --git a/libsanitizer/asan/asan_globals.cpp b/libsanitizer/asan/asan_globals.cpp
> >> index e045c31cd1c..9d7dbc6f264 100644
> >> --- a/libsanitizer/asan/asan_globals.cpp
> >> +++ b/libsanitizer/asan/asan_globals.cpp
> >> @@ -154,6 +154,23 @@ static void CheckODRViolationViaIndicator(const Global *g) {
> >> }
> >> }
> >>
> >> +// Check ODR violation for given global G by checking if it's already poisoned.
> >> +// We use this method in case compiler doesn't use private aliases for global
> >> +// variables.
> >> +static void CheckODRViolationViaPoisoning(const Global *g) {
> >> + if (__asan_region_is_poisoned(g->beg, g->size_with_redzone)) {
> >> + // This check may not be enough: if the first global is much larger
> >> + // the entire redzone of the second global may be within the first global.
> >> + for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) {
> >> + if (g->beg == l->g->beg &&
> >> + (flags()->detect_odr_violation >= 2 || g->size != l->g->size) &&
> >> + !IsODRViolationSuppressed(g->name))
> >> + ReportODRViolation(g, FindRegistrationSite(g),
> >> + l->g, FindRegistrationSite(l->g));
> >> + }
> >> + }
> >> +}
> >> +
> >> // Clang provides two different ways for global variables protection:
> >> // it can poison the global itself or its private alias. In former
> >> // case we may poison same symbol multiple times, that can help us to
> >> @@ -199,6 +216,8 @@ static void RegisterGlobal(const Global *g) {
> >> // where two globals with the same name are defined in different modules.
> >> if (UseODRIndicator(g))
> >> CheckODRViolationViaIndicator(g);
> >> + else
> >> + CheckODRViolationViaPoisoning(g);
> >> }
> >> if (CanPoisonMemory())
> >> PoisonRedZones(*g);
> >> diff --git a/libsanitizer/asan/asan_interceptors.cpp b/libsanitizer/asan/asan_interceptors.cpp
> >> index 4e68b3b0b47..9db7db89fa1 100644
> >> --- a/libsanitizer/asan/asan_interceptors.cpp
> >> +++ b/libsanitizer/asan/asan_interceptors.cpp
> >> @@ -191,20 +191,11 @@ DECLARE_REAL_AND_INTERCEPTOR(void, free, void *)
> >> #include "sanitizer_common/sanitizer_common_syscalls.inc"
> >> #include "sanitizer_common/sanitizer_syscalls_netbsd.inc"
> >>
> >> -struct ThreadStartParam {
> >> - atomic_uintptr_t t;
> >> - atomic_uintptr_t is_registered;
> >> -};
> >> -
> >> #if ASAN_INTERCEPT_PTHREAD_CREATE
> >> static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) {
> >> - ThreadStartParam *param = reinterpret_cast<ThreadStartParam *>(arg);
> >> - AsanThread *t = nullptr;
> >> - while ((t = reinterpret_cast<AsanThread *>(
> >> - atomic_load(¶m->t, memory_order_acquire))) == nullptr)
> >> - internal_sched_yield();
> >> + AsanThread *t = (AsanThread *)arg;
> >> SetCurrentThread(t);
> >> - return t->ThreadStart(GetTid(), ¶m->is_registered);
> >> + return t->ThreadStart(GetTid());
> >> }
> >>
> >> INTERCEPTOR(int, pthread_create, void *thread,
> >> @@ -217,9 +208,11 @@ INTERCEPTOR(int, pthread_create, void *thread,
> >> int detached = 0;
> >> if (attr)
> >> REAL(pthread_attr_getdetachstate)(attr, &detached);
> >> - ThreadStartParam param;
> >> - atomic_store(¶m.t, 0, memory_order_relaxed);
> >> - atomic_store(¶m.is_registered, 0, memory_order_relaxed);
> >> +
> >> + u32 current_tid = GetCurrentTidOrInvalid();
> >> + AsanThread *t =
> >> + AsanThread::Create(start_routine, arg, current_tid, &stack, detached);
> >> +
> >> int result;
> >> {
> >> // Ignore all allocations made by pthread_create: thread stack/TLS may be
> >> @@ -229,21 +222,13 @@ INTERCEPTOR(int, pthread_create, void *thread,
> >> #if CAN_SANITIZE_LEAKS
> >> __lsan::ScopedInterceptorDisabler disabler;
> >> #endif
> >> - result = REAL(pthread_create)(thread, attr, asan_thread_start, ¶m);
> >> + result = REAL(pthread_create)(thread, attr, asan_thread_start, t);
> >> }
> >> - if (result == 0) {
> >> - u32 current_tid = GetCurrentTidOrInvalid();
> >> - AsanThread *t =
> >> - AsanThread::Create(start_routine, arg, current_tid, &stack, detached);
> >> - atomic_store(¶m.t, reinterpret_cast<uptr>(t), memory_order_release);
> >> - // Wait until the AsanThread object is initialized and the ThreadRegistry
> >> - // entry is in "started" state. One reason for this is that after this
> >> - // interceptor exits, the child thread's stack may be the only thing holding
> >> - // the |arg| pointer. This may cause LSan to report a leak if leak checking
> >> - // happens at a point when the interceptor has already exited, but the stack
> >> - // range for the child thread is not yet known.
> >> - while (atomic_load(¶m.is_registered, memory_order_acquire) == 0)
> >> - internal_sched_yield();
> >> + if (result != 0) {
> >> + // If the thread didn't start delete the AsanThread to avoid leaking it.
> >> + // Note AsanThreadContexts never get destroyed so the AsanThreadContext
> >> + // that was just created for the AsanThread is wasted.
> >> + t->Destroy();
> >> }
> >> return result;
> >> }
> >> diff --git a/libsanitizer/asan/asan_interceptors.h b/libsanitizer/asan/asan_interceptors.h
> >> index 56dc34b7d93..e8c58c2dc6b 100644
> >> --- a/libsanitizer/asan/asan_interceptors.h
> >> +++ b/libsanitizer/asan/asan_interceptors.h
> >> @@ -60,7 +60,7 @@ void InitializePlatformInterceptors();
> >> # define ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX 0
> >> #endif
> >>
> >> -#if (SANITIZER_LINUX && !SANITIZER_ANDROID) || SANITIZER_SOLARIS
> >> +#if SANITIZER_GLIBC || SANITIZER_SOLARIS
> >> # define ASAN_INTERCEPT_SWAPCONTEXT 1
> >> #else
> >> # define ASAN_INTERCEPT_SWAPCONTEXT 0
> >> @@ -72,7 +72,7 @@ void InitializePlatformInterceptors();
> >> # define ASAN_INTERCEPT_SIGLONGJMP 0
> >> #endif
> >>
> >> -#if SANITIZER_LINUX && !SANITIZER_ANDROID
> >> +#if SANITIZER_GLIBC
> >> # define ASAN_INTERCEPT___LONGJMP_CHK 1
> >> #else
> >> # define ASAN_INTERCEPT___LONGJMP_CHK 0
> >> @@ -81,12 +81,7 @@ void InitializePlatformInterceptors();
> >> #if ASAN_HAS_EXCEPTIONS && !SANITIZER_WINDOWS && !SANITIZER_SOLARIS && \
> >> !SANITIZER_NETBSD
> >> # define ASAN_INTERCEPT___CXA_THROW 1
> >> -# if ! defined(ASAN_HAS_CXA_RETHROW_PRIMARY_EXCEPTION) \
> >> - || ASAN_HAS_CXA_RETHROW_PRIMARY_EXCEPTION
> >> -# define ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION 1
> >> -# else
> >> -# define ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION 0
> >> -# endif
> >> +# define ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION 1
> >> # if defined(_GLIBCXX_SJLJ_EXCEPTIONS) || (SANITIZER_IOS && defined(__arm__))
> >> # define ASAN_INTERCEPT__UNWIND_SJLJ_RAISEEXCEPTION 1
> >> # else
> >> @@ -111,7 +106,7 @@ void InitializePlatformInterceptors();
> >> # define ASAN_INTERCEPT_ATEXIT 0
> >> #endif
> >>
> >> -#if SANITIZER_LINUX && !SANITIZER_ANDROID
> >> +#if SANITIZER_GLIBC
> >> # define ASAN_INTERCEPT___STRDUP 1
> >> #else
> >> # define ASAN_INTERCEPT___STRDUP 0
> >> @@ -139,10 +134,10 @@ DECLARE_REAL(uptr, strnlen, const char *s, uptr maxlen)
> >> DECLARE_REAL(char*, strstr, const char *s1, const char *s2)
> >>
> >> #if !SANITIZER_MAC
> >> -#define ASAN_INTERCEPT_FUNC(name) \
> >> - do { \
> >> - if (!INTERCEPT_FUNCTION(name)) \
> >> - VReport(1, "AddressSanitizer: failed to intercept '%s'\n'", #name); \
> >> +#define ASAN_INTERCEPT_FUNC(name) \
> >> + do { \
> >> + if (!INTERCEPT_FUNCTION(name)) \
> >> + VReport(1, "AddressSanitizer: failed to intercept '%s'\n", #name); \
> >> } while (0)
> >> #define ASAN_INTERCEPT_FUNC_VER(name, ver) \
> >> do { \
> >> diff --git a/libsanitizer/asan/asan_linux.cpp b/libsanitizer/asan/asan_linux.cpp
> >> index fb1a442b3d4..4bcbe5d02e3 100644
> >> --- a/libsanitizer/asan/asan_linux.cpp
> >> +++ b/libsanitizer/asan/asan_linux.cpp
> >> @@ -55,6 +55,7 @@ extern Elf_Dyn _DYNAMIC;
> >> #else
> >> #include <sys/ucontext.h>
> >> #include <link.h>
> >> +extern ElfW(Dyn) _DYNAMIC[];
> >> #endif
> >>
> >> // x86-64 FreeBSD 9.2 and older define 'ucontext_t' incorrectly in
> >> @@ -84,7 +85,7 @@ bool IsSystemHeapAddress (uptr addr) { return false; }
> >>
> >> void *AsanDoesNotSupportStaticLinkage() {
> >> // This will fail to link with -static.
> >> - return &_DYNAMIC; // defined in link.h
> >> + return &_DYNAMIC;
> >> }
> >>
> >> #if ASAN_PREMAP_SHADOW
> >> diff --git a/libsanitizer/asan/asan_mapping.h b/libsanitizer/asan/asan_mapping.h
> >> index a7136de60d2..455e2364cd0 100644
> >> --- a/libsanitizer/asan/asan_mapping.h
> >> +++ b/libsanitizer/asan/asan_mapping.h
> >> @@ -72,6 +72,13 @@
> >> // || `[0x2000000000, 0x23ffffffff]` || LowShadow ||
> >> // || `[0x0000000000, 0x1fffffffff]` || LowMem ||
> >> //
> >> +// Default Linux/RISCV64 Sv39 mapping:
> >> +// || `[0x1555550000, 0x3fffffffff]` || HighMem ||
> >> +// || `[0x0fffffa000, 0x1555555fff]` || HighShadow ||
> >> +// || `[0x0effffa000, 0x0fffff9fff]` || ShadowGap ||
> >> +// || `[0x0d55550000, 0x0effff9fff]` || LowShadow ||
> >> +// || `[0x0000000000, 0x0d5554ffff]` || LowMem ||
> >> +//
> >> // Default Linux/AArch64 (39-bit VMA) mapping:
> >> // || `[0x2000000000, 0x7fffffffff]` || highmem ||
> >> // || `[0x1400000000, 0x1fffffffff]` || highshadow ||
> >> @@ -79,20 +86,6 @@
> >> // || `[0x1000000000, 0x11ffffffff]` || lowshadow ||
> >> // || `[0x0000000000, 0x0fffffffff]` || lowmem ||
> >> //
> >> -// RISC-V has only 38 bits for task size
> >> -// Low mem size is set with kRiscv64_ShadowOffset64 in
> >> -// compiler-rt/lib/asan/asan_allocator.h and in
> >> -// llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp with
> >> -// kRiscv64_ShadowOffset64, High mem top border is set with
> >> -// GetMaxVirtualAddress() in
> >> -// compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp
> >> -// Default Linux/RISCV64 Sv39/Sv48 mapping:
> >> -// || `[0x000820000000, 0x003fffffffff]` || HighMem ||
> >> -// || `[0x000124000000, 0x00081fffffff]` || HighShadow ||
> >> -// || `[0x000024000000, 0x000123ffffff]` || ShadowGap ||
> >> -// || `[0x000020000000, 0x000023ffffff]` || LowShadow ||
> >> -// || `[0x000000000000, 0x00001fffffff]` || LowMem ||
> >> -//
> >> // Default Linux/AArch64 (42-bit VMA) mapping:
> >> // || `[0x10000000000, 0x3ffffffffff]` || highmem ||
> >> // || `[0x0a000000000, 0x0ffffffffff]` || highshadow ||
> >> @@ -175,10 +168,10 @@ static const u64 kDefaultShadowOffset64 = 1ULL << 44;
> >> static const u64 kDefaultShort64bitShadowOffset =
> >> 0x7FFFFFFF & (~0xFFFULL << kDefaultShadowScale); // < 2G.
> >> static const u64 kAArch64_ShadowOffset64 = 1ULL << 36;
> >> -static const u64 kRiscv64_ShadowOffset64 = 0x20000000;
> >> +static const u64 kRiscv64_ShadowOffset64 = 0xd55550000;
> >> static const u64 kMIPS32_ShadowOffset32 = 0x0aaa0000;
> >> static const u64 kMIPS64_ShadowOffset64 = 1ULL << 37;
> >> -static const u64 kPPC64_ShadowOffset64 = 1ULL << 41;
> >> +static const u64 kPPC64_ShadowOffset64 = 1ULL << 44;
> >> static const u64 kSystemZ_ShadowOffset64 = 1ULL << 52;
> >> static const u64 kSPARC64_ShadowOffset64 = 1ULL << 43; // 0x80000000000
> >> static const u64 kFreeBSD_ShadowOffset32 = 1ULL << 30; // 0x40000000
> >> diff --git a/libsanitizer/asan/asan_new_delete.cpp b/libsanitizer/asan/asan_new_delete.cpp
> >> index 5dfcc00fd5d..92a8648452b 100644
> >> --- a/libsanitizer/asan/asan_new_delete.cpp
> >> +++ b/libsanitizer/asan/asan_new_delete.cpp
> >> @@ -45,7 +45,7 @@ COMMENT_EXPORT("??_V@YAXPAX@Z") // operator delete[]
> >> #endif
> >> #undef COMMENT_EXPORT
> >> #else
> >> -#define CXX_OPERATOR_ATTRIBUTE INTERCEPTOR_ATTRIBUTE
> >> +#define CXX_OPERATOR_ATTRIBUTE INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
> >> #endif
> >>
> >> using namespace __asan;
> >> diff --git a/libsanitizer/asan/asan_poisoning.cpp b/libsanitizer/asan/asan_poisoning.cpp
> >> index 44f872ef619..fa149ecfde6 100644
> >> --- a/libsanitizer/asan/asan_poisoning.cpp
> >> +++ b/libsanitizer/asan/asan_poisoning.cpp
> >> @@ -364,7 +364,7 @@ void __sanitizer_annotate_contiguous_container(const void *beg_p,
> >> &stack);
> >> }
> >> CHECK_LE(end - beg,
> >> - FIRST_32_SECOND_64(1UL << 30, 1ULL << 34)); // Sanity check.
> >> + FIRST_32_SECOND_64(1UL << 30, 1ULL << 40)); // Sanity check.
> >>
> >> uptr a = RoundDownTo(Min(old_mid, new_mid), granularity);
> >> uptr c = RoundUpTo(Max(old_mid, new_mid), granularity);
> >> diff --git a/libsanitizer/asan/asan_posix.cpp b/libsanitizer/asan/asan_posix.cpp
> >> index d7f19d84654..63ad735f8bb 100644
> >> --- a/libsanitizer/asan/asan_posix.cpp
> >> +++ b/libsanitizer/asan/asan_posix.cpp
> >> @@ -56,7 +56,7 @@ bool PlatformUnpoisonStacks() {
> >> if (signal_stack.ss_flags != SS_ONSTACK)
> >> return false;
> >>
> >> - // Since we're on the signal altnerate stack, we cannot find the DEFAULT
> >> + // Since we're on the signal alternate stack, we cannot find the DEFAULT
> >> // stack bottom using a local variable.
> >> uptr default_bottom, tls_addr, tls_size, stack_size;
> >> GetThreadStackAndTls(/*main=*/false, &default_bottom, &stack_size, &tls_addr,
> >> diff --git a/libsanitizer/asan/asan_rtl.cpp b/libsanitizer/asan/asan_rtl.cpp
> >> index 7b5a929963c..e715d774228 100644
> >> --- a/libsanitizer/asan/asan_rtl.cpp
> >> +++ b/libsanitizer/asan/asan_rtl.cpp
> >> @@ -62,19 +62,9 @@ static void AsanDie() {
> >> }
> >> }
> >>
> >> -static void AsanCheckFailed(const char *file, int line, const char *cond,
> >> - u64 v1, u64 v2) {
> >> - Report("AddressSanitizer CHECK failed: %s:%d \"%s\" (0x%zx, 0x%zx)\n", file,
> >> - line, cond, (uptr)v1, (uptr)v2);
> >> -
> >> - // Print a stack trace the first time we come here. Otherwise, we probably
> >> - // failed a CHECK during symbolization.
> >> - static atomic_uint32_t num_calls;
> >> - if (atomic_fetch_add(&num_calls, 1, memory_order_relaxed) == 0) {
> >> - PRINT_CURRENT_STACK_CHECK();
> >> - }
> >> -
> >> - Die();
> >> +static void CheckUnwind() {
> >> + GET_STACK_TRACE(kStackTraceMax, common_flags()->fast_unwind_on_check);
> >> + stack.Print();
> >> }
> >>
> >> // -------------------------- Globals --------------------- {{{1
> >> @@ -432,7 +422,7 @@ static void AsanInitInternal() {
> >>
> >> // Install tool-specific callbacks in sanitizer_common.
> >> AddDieCallback(AsanDie);
> >> - SetCheckFailedCallback(AsanCheckFailed);
> >> + SetCheckUnwindCallback(CheckUnwind);
> >> SetPrintfAndReportCallback(AppendToErrorMessageBuffer);
> >>
> >> __sanitizer_set_report_path(common_flags()->log_path);
> >> @@ -568,7 +558,7 @@ void UnpoisonStack(uptr bottom, uptr top, const char *type) {
> >> type, top, bottom, top - bottom, top - bottom);
> >> return;
> >> }
> >> - PoisonShadow(bottom, top - bottom, 0);
> >> + PoisonShadow(bottom, RoundUpTo(top - bottom, SHADOW_GRANULARITY), 0);
> >> }
> >>
> >> static void UnpoisonDefaultStack() {
> >> diff --git a/libsanitizer/asan/asan_stack.h b/libsanitizer/asan/asan_stack.h
> >> index 47ca85a1644..b9575d2f427 100644
> >> --- a/libsanitizer/asan/asan_stack.h
> >> +++ b/libsanitizer/asan/asan_stack.h
> >> @@ -54,9 +54,6 @@ u32 GetMallocContextSize();
> >> #define GET_STACK_TRACE_FATAL_HERE \
> >> GET_STACK_TRACE(kStackTraceMax, common_flags()->fast_unwind_on_fatal)
> >>
> >> -#define GET_STACK_TRACE_CHECK_HERE \
> >> - GET_STACK_TRACE(kStackTraceMax, common_flags()->fast_unwind_on_check)
> >> -
> >> #define GET_STACK_TRACE_THREAD \
> >> GET_STACK_TRACE(kStackTraceMax, true)
> >>
> >> @@ -71,10 +68,4 @@ u32 GetMallocContextSize();
> >> stack.Print(); \
> >> }
> >>
> >> -#define PRINT_CURRENT_STACK_CHECK() \
> >> - { \
> >> - GET_STACK_TRACE_CHECK_HERE; \
> >> - stack.Print(); \
> >> - }
> >> -
> >> #endif // ASAN_STACK_H
> >> diff --git a/libsanitizer/asan/asan_thread.cpp b/libsanitizer/asan/asan_thread.cpp
> >> index fb09af0ecca..9c3c86f5735 100644
> >> --- a/libsanitizer/asan/asan_thread.cpp
> >> +++ b/libsanitizer/asan/asan_thread.cpp
> >> @@ -100,18 +100,27 @@ void AsanThread::Destroy() {
> >> int tid = this->tid();
> >> VReport(1, "T%d exited\n", tid);
> >>
> >> - malloc_storage().CommitBack();
> >> - if (common_flags()->use_sigaltstack) UnsetAlternateSignalStack();
> >> - asanThreadRegistry().FinishThread(tid);
> >> - FlushToDeadThreadStats(&stats_);
> >> - // We also clear the shadow on thread destruction because
> >> - // some code may still be executing in later TSD destructors
> >> - // and we don't want it to have any poisoned stack.
> >> - ClearShadowForThreadStackAndTLS();
> >> - DeleteFakeStack(tid);
> >> + bool was_running =
> >> + (asanThreadRegistry().FinishThread(tid) == ThreadStatusRunning);
> >> + if (was_running) {
> >> + if (AsanThread *thread = GetCurrentThread())
> >> + CHECK_EQ(this, thread);
> >> + malloc_storage().CommitBack();
> >> + if (common_flags()->use_sigaltstack)
> >> + UnsetAlternateSignalStack();
> >> + FlushToDeadThreadStats(&stats_);
> >> + // We also clear the shadow on thread destruction because
> >> + // some code may still be executing in later TSD destructors
> >> + // and we don't want it to have any poisoned stack.
> >> + ClearShadowForThreadStackAndTLS();
> >> + DeleteFakeStack(tid);
> >> + } else {
> >> + CHECK_NE(this, GetCurrentThread());
> >> + }
> >> uptr size = RoundUpTo(sizeof(AsanThread), GetPageSizeCached());
> >> UnmapOrDie(this, size);
> >> - DTLS_Destroy();
> >> + if (was_running)
> >> + DTLS_Destroy();
> >> }
> >>
> >> void AsanThread::StartSwitchFiber(FakeStack **fake_stack_save, uptr bottom,
> >> @@ -219,7 +228,7 @@ FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() {
> >> }
> >>
> >> void AsanThread::Init(const InitOptions *options) {
> >> - DCHECK_NE(tid(), ThreadRegistry::kUnknownTid);
> >> + DCHECK_NE(tid(), kInvalidTid);
> >> next_stack_top_ = next_stack_bottom_ = 0;
> >> atomic_store(&stack_switching_, false, memory_order_release);
> >> CHECK_EQ(this->stack_size(), 0U);
> >> @@ -253,12 +262,9 @@ void AsanThread::Init(const InitOptions *options) {
> >> // SetThreadStackAndTls.
> >> #if !SANITIZER_FUCHSIA && !SANITIZER_RTEMS
> >>
> >> -thread_return_t AsanThread::ThreadStart(
> >> - tid_t os_id, atomic_uintptr_t *signal_thread_is_registered) {
> >> +thread_return_t AsanThread::ThreadStart(tid_t os_id) {
> >> Init();
> >> asanThreadRegistry().StartThread(tid(), os_id, ThreadType::Regular, nullptr);
> >> - if (signal_thread_is_registered)
> >> - atomic_store(signal_thread_is_registered, 1, memory_order_release);
> >>
> >> if (common_flags()->use_sigaltstack) SetAlternateSignalStack();
> >>
> >> @@ -285,11 +291,10 @@ thread_return_t AsanThread::ThreadStart(
> >>
> >> AsanThread *CreateMainThread() {
> >> AsanThread *main_thread = AsanThread::Create(
> >> - /* start_routine */ nullptr, /* arg */ nullptr, /* parent_tid */ 0,
> >> + /* start_routine */ nullptr, /* arg */ nullptr, /* parent_tid */ kMainTid,
> >> /* stack */ nullptr, /* detached */ true);
> >> SetCurrentThread(main_thread);
> >> - main_thread->ThreadStart(internal_getpid(),
> >> - /* signal_thread_is_registered */ nullptr);
> >> + main_thread->ThreadStart(internal_getpid());
> >> return main_thread;
> >> }
> >>
> >> @@ -300,9 +305,9 @@ void AsanThread::SetThreadStackAndTls(const InitOptions *options) {
> >> DCHECK_EQ(options, nullptr);
> >> uptr tls_size = 0;
> >> uptr stack_size = 0;
> >> - GetThreadStackAndTls(tid() == 0, &stack_bottom_, &stack_size, &tls_begin_,
> >> - &tls_size);
> >> - stack_top_ = stack_bottom_ + stack_size;
> >> + GetThreadStackAndTls(tid() == kMainTid, &stack_bottom_, &stack_size,
> >> + &tls_begin_, &tls_size);
> >> + stack_top_ = RoundDownTo(stack_bottom_ + stack_size, SHADOW_GRANULARITY);
> >> tls_end_ = tls_begin_ + tls_size;
> >> dtls_ = DTLS_Get();
> >>
> >> @@ -426,7 +431,7 @@ AsanThread *GetCurrentThread() {
> >> // address. We are not entirely sure that we have correct main thread
> >> // limits, so only do this magic on Android, and only if the found thread
> >> // is the main thread.
> >> - AsanThreadContext *tctx = GetThreadContextByTidLocked(0);
> >> + AsanThreadContext *tctx = GetThreadContextByTidLocked(kMainTid);
> >> if (tctx && ThreadStackContainsAddress(tctx, &context)) {
> >> SetCurrentThread(tctx->thread);
> >> return tctx->thread;
> >> @@ -463,7 +468,7 @@ AsanThread *FindThreadByStackAddress(uptr addr) {
> >> void EnsureMainThreadIDIsCorrect() {
> >> AsanThreadContext *context =
> >> reinterpret_cast<AsanThreadContext *>(AsanTSDGet());
> >> - if (context && (context->tid == 0))
> >> + if (context && (context->tid == kMainTid))
> >> context->os_id = GetTid();
> >> }
> >>
> >> diff --git a/libsanitizer/asan/asan_thread.h b/libsanitizer/asan/asan_thread.h
> >> index ea58de4216a..200069ce0dd 100644
> >> --- a/libsanitizer/asan/asan_thread.h
> >> +++ b/libsanitizer/asan/asan_thread.h
> >> @@ -28,7 +28,6 @@ struct DTLS;
> >>
> >> namespace __asan {
> >>
> >> -const u32 kInvalidTid = 0xffffff; // Must fit into 24 bits.
> >> const u32 kMaxNumberOfThreads = (1 << 22); // 4M
> >>
> >> class AsanThread;
> >> @@ -69,8 +68,7 @@ class AsanThread {
> >> struct InitOptions;
> >> void Init(const InitOptions *options = nullptr);
> >>
> >> - thread_return_t ThreadStart(tid_t os_id,
> >> - atomic_uintptr_t *signal_thread_is_registered);
> >> + thread_return_t ThreadStart(tid_t os_id);
> >>
> >> uptr stack_top();
> >> uptr stack_bottom();
> >> @@ -132,6 +130,8 @@ class AsanThread {
> >>
> >> void *extra_spill_area() { return &extra_spill_area_; }
> >>
> >> + void *get_arg() { return arg_; }
> >> +
> >> private:
> >> // NOTE: There is no AsanThread constructor. It is allocated
> >> // via mmap() and *must* be valid in zero-initialized state.
> >> diff --git a/libsanitizer/asan/asan_win.cpp b/libsanitizer/asan/asan_win.cpp
> >> index 8044ae16ff9..1577c83cf99 100644
> >> --- a/libsanitizer/asan/asan_win.cpp
> >> +++ b/libsanitizer/asan/asan_win.cpp
> >> @@ -134,7 +134,7 @@ INTERCEPTOR(int, _except_handler4, void *a, void *b, void *c, void *d) {
> >> static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) {
> >> AsanThread *t = (AsanThread *)arg;
> >> SetCurrentThread(t);
> >> - return t->ThreadStart(GetTid(), /* signal_thread_is_registered */ nullptr);
> >> + return t->ThreadStart(GetTid());
> >> }
> >>
> >> INTERCEPTOR_WINAPI(HANDLE, CreateThread, LPSECURITY_ATTRIBUTES security,
> >> diff --git a/libsanitizer/builtins/assembly.h b/libsanitizer/builtins/assembly.h
> >> index f437cb87f60..9c015059af5 100644
> >> --- a/libsanitizer/builtins/assembly.h
> >> +++ b/libsanitizer/builtins/assembly.h
> >> @@ -14,8 +14,8 @@
> >> #ifndef COMPILERRT_ASSEMBLY_H
> >> #define COMPILERRT_ASSEMBLY_H
> >>
> >> -#if defined(__POWERPC__) || defined(__powerpc__) || defined(__ppc__)
> >> -#define SEPARATOR @
> >> +#if defined(__APPLE__) && defined(__aarch64__)
> >> +#define SEPARATOR %%
> >> #else
> >> #define SEPARATOR ;
> >> #endif
> >> @@ -35,14 +35,14 @@
> >> #define HIDDEN(name) .hidden name
> >> #define LOCAL_LABEL(name) .L_##name
> >> #define FILE_LEVEL_DIRECTIVE
> >> -#if defined(__arm__)
> >> +#if defined(__arm__) || defined(__aarch64__)
> >> #define SYMBOL_IS_FUNC(name) .type name,%function
> >> #else
> >> #define SYMBOL_IS_FUNC(name) .type name,@function
> >> #endif
> >> #define CONST_SECTION .section .rodata
> >>
> >> -#if defined(__GNU__) || defined(__FreeBSD__) || defined(__Fuchsia__) || \
> >> +#if defined(__GNU__) || defined(__FreeBSD__) || defined(__Fuchsia__) || \
> >> defined(__linux__)
> >> #define NO_EXEC_STACK_DIRECTIVE .section .note.GNU-stack,"",%progbits
> >> #else
> >> @@ -65,6 +65,68 @@
> >>
> >> #endif
> >>
> >> +#if defined(__arm__) || defined(__aarch64__)
> >> +#define FUNC_ALIGN \
> >> + .text SEPARATOR \
> >> + .balign 16 SEPARATOR
> >> +#else
> >> +#define FUNC_ALIGN
> >> +#endif
> >> +
> >> +// BTI and PAC gnu property note
> >> +#define NT_GNU_PROPERTY_TYPE_0 5
> >> +#define GNU_PROPERTY_AARCH64_FEATURE_1_AND 0xc0000000
> >> +#define GNU_PROPERTY_AARCH64_FEATURE_1_BTI 1
> >> +#define GNU_PROPERTY_AARCH64_FEATURE_1_PAC 2
> >> +
> >> +#if defined(__ARM_FEATURE_BTI_DEFAULT)
> >> +#define BTI_FLAG GNU_PROPERTY_AARCH64_FEATURE_1_BTI
> >> +#else
> >> +#define BTI_FLAG 0
> >> +#endif
> >> +
> >> +#if __ARM_FEATURE_PAC_DEFAULT & 3
> >> +#define PAC_FLAG GNU_PROPERTY_AARCH64_FEATURE_1_PAC
> >> +#else
> >> +#define PAC_FLAG 0
> >> +#endif
> >> +
> >> +#define GNU_PROPERTY(type, value) \
> >> + .pushsection .note.gnu.property, "a" SEPARATOR \
> >> + .p2align 3 SEPARATOR \
> >> + .word 4 SEPARATOR \
> >> + .word 16 SEPARATOR \
> >> + .word NT_GNU_PROPERTY_TYPE_0 SEPARATOR \
> >> + .asciz "GNU" SEPARATOR \
> >> + .word type SEPARATOR \
> >> + .word 4 SEPARATOR \
> >> + .word value SEPARATOR \
> >> + .word 0 SEPARATOR \
> >> + .popsection
> >> +
> >> +#if BTI_FLAG != 0
> >> +#define BTI_C hint #34
> >> +#define BTI_J hint #36
> >> +#else
> >> +#define BTI_C
> >> +#define BTI_J
> >> +#endif
> >> +
> >> +#if (BTI_FLAG | PAC_FLAG) != 0
> >> +#define GNU_PROPERTY_BTI_PAC \
> >> + GNU_PROPERTY(GNU_PROPERTY_AARCH64_FEATURE_1_AND, BTI_FLAG | PAC_FLAG)
> >> +#else
> >> +#define GNU_PROPERTY_BTI_PAC
> >> +#endif
> >> +
> >> +#if defined(__clang__) || defined(__GCC_HAVE_DWARF2_CFI_ASM)
> >> +#define CFI_START .cfi_startproc
> >> +#define CFI_END .cfi_endproc
> >> +#else
> >> +#define CFI_START
> >> +#define CFI_END
> >> +#endif
> >> +
> >> #if defined(__arm__)
> >>
> >> // Determine actual [ARM][THUMB[1][2]] ISA using compiler predefined macros:
> >> @@ -131,15 +193,24 @@
> >> #define DEFINE_CODE_STATE
> >> #endif
> >>
> >> -#define GLUE2(a, b) a##b
> >> -#define GLUE(a, b) GLUE2(a, b)
> >> +#define GLUE2_(a, b) a##b
> >> +#define GLUE(a, b) GLUE2_(a, b)
> >> +#define GLUE2(a, b) GLUE2_(a, b)
> >> +#define GLUE3_(a, b, c) a##b##c
> >> +#define GLUE3(a, b, c) GLUE3_(a, b, c)
> >> +#define GLUE4_(a, b, c, d) a##b##c##d
> >> +#define GLUE4(a, b, c, d) GLUE4_(a, b, c, d)
> >> +
> >> #define SYMBOL_NAME(name) GLUE(__USER_LABEL_PREFIX__, name)
> >>
> >> #ifdef VISIBILITY_HIDDEN
> >> #define DECLARE_SYMBOL_VISIBILITY(name) \
> >> HIDDEN(SYMBOL_NAME(name)) SEPARATOR
> >> +#define DECLARE_SYMBOL_VISIBILITY_UNMANGLED(name) \
> >> + HIDDEN(name) SEPARATOR
> >> #else
> >> #define DECLARE_SYMBOL_VISIBILITY(name)
> >> +#define DECLARE_SYMBOL_VISIBILITY_UNMANGLED(name)
> >> #endif
> >>
> >> #define DEFINE_COMPILERRT_FUNCTION(name) \
> >> @@ -177,6 +248,16 @@
> >> DECLARE_FUNC_ENCODING \
> >> name:
> >>
> >> +#define DEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(name) \
> >> + DEFINE_CODE_STATE \
> >> + FUNC_ALIGN \
> >> + .globl name SEPARATOR \
> >> + SYMBOL_IS_FUNC(name) SEPARATOR \
> >> + DECLARE_SYMBOL_VISIBILITY_UNMANGLED(name) SEPARATOR \
> >> + CFI_START SEPARATOR \
> >> + DECLARE_FUNC_ENCODING \
> >> + name: SEPARATOR BTI_C
> >> +
> >> #define DEFINE_COMPILERRT_FUNCTION_ALIAS(name, target) \
> >> .globl SYMBOL_NAME(name) SEPARATOR \
> >> SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \
> >> @@ -193,8 +274,13 @@
> >> #ifdef __ELF__
> >> #define END_COMPILERRT_FUNCTION(name) \
> >> .size SYMBOL_NAME(name), . - SYMBOL_NAME(name)
> >> +#define END_COMPILERRT_OUTLINE_FUNCTION(name) \
> >> + CFI_END SEPARATOR \
> >> + .size SYMBOL_NAME(name), . - SYMBOL_NAME(name)
> >> #else
> >> #define END_COMPILERRT_FUNCTION(name)
> >> +#define END_COMPILERRT_OUTLINE_FUNCTION(name) \
> >> + CFI_END
> >> #endif
> >>
> >> #endif // COMPILERRT_ASSEMBLY_H
> >> diff --git a/libsanitizer/hwasan/hwasan.cpp b/libsanitizer/hwasan/hwasan.cpp
> >> index c5322110cb6..8d6c25261b8 100644
> >> --- a/libsanitizer/hwasan/hwasan.cpp
> >> +++ b/libsanitizer/hwasan/hwasan.cpp
> >> @@ -128,16 +128,11 @@ static void InitializeFlags() {
> >> if (common_flags()->help) parser.PrintFlagDescriptions();
> >> }
> >>
> >> -static void HWAsanCheckFailed(const char *file, int line, const char *cond,
> >> - u64 v1, u64 v2) {
> >> - Report("HWAddressSanitizer CHECK failed: %s:%d \"%s\" (0x%zx, 0x%zx)\n", file,
> >> - line, cond, (uptr)v1, (uptr)v2);
> >> - PRINT_CURRENT_STACK_CHECK();
> >> - Die();
> >> +static void CheckUnwind() {
> >> + GET_FATAL_STACK_TRACE_PC_BP(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME());
> >> + stack.Print();
> >> }
> >>
> >> -static constexpr uptr kMemoryUsageBufferSize = 4096;
> >> -
> >> static void HwasanFormatMemoryUsage(InternalScopedString &s) {
> >> HwasanThreadList &thread_list = hwasanThreadList();
> >> auto thread_stats = thread_list.GetThreadStats();
> >> @@ -155,6 +150,8 @@ static void HwasanFormatMemoryUsage(InternalScopedString &s) {
> >> }
> >>
> >> #if SANITIZER_ANDROID
> >> +static constexpr uptr kMemoryUsageBufferSize = 4096;
> >> +
> >> static char *memory_usage_buffer = nullptr;
> >>
> >> static void InitMemoryUsage() {
> >> @@ -171,7 +168,7 @@ void UpdateMemoryUsage() {
> >> return;
> >> if (!memory_usage_buffer)
> >> InitMemoryUsage();
> >> - InternalScopedString s(kMemoryUsageBufferSize);
> >> + InternalScopedString s;
> >> HwasanFormatMemoryUsage(s);
> >> internal_strncpy(memory_usage_buffer, s.data(), kMemoryUsageBufferSize - 1);
> >> memory_usage_buffer[kMemoryUsageBufferSize - 1] = '\0';
> >> @@ -271,7 +268,7 @@ void __hwasan_init() {
> >> InitializeFlags();
> >>
> >> // Install tool-specific callbacks in sanitizer_common.
> >> - SetCheckFailedCallback(HWAsanCheckFailed);
> >> + SetCheckUnwindCallback(CheckUnwind);
> >>
> >> __sanitizer_set_report_path(common_flags()->log_path);
> >>
> >> @@ -493,7 +490,7 @@ extern "C" void *__hwasan_extra_spill_area() {
> >> }
> >>
> >> void __hwasan_print_memory_usage() {
> >> - InternalScopedString s(kMemoryUsageBufferSize);
> >> + InternalScopedString s;
> >> HwasanFormatMemoryUsage(s);
> >> Printf("%s\n", s.data());
> >> }
> >> diff --git a/libsanitizer/hwasan/hwasan.h b/libsanitizer/hwasan/hwasan.h
> >> index d4521efd089..8515df559f3 100644
> >> --- a/libsanitizer/hwasan/hwasan.h
> >> +++ b/libsanitizer/hwasan/hwasan.h
> >> @@ -14,11 +14,12 @@
> >> #ifndef HWASAN_H
> >> #define HWASAN_H
> >>
> >> +#include "hwasan_flags.h"
> >> +#include "hwasan_interface_internal.h"
> >> +#include "sanitizer_common/sanitizer_common.h"
> >> #include "sanitizer_common/sanitizer_flags.h"
> >> #include "sanitizer_common/sanitizer_internal_defs.h"
> >> #include "sanitizer_common/sanitizer_stacktrace.h"
> >> -#include "hwasan_interface_internal.h"
> >> -#include "hwasan_flags.h"
> >> #include "ubsan/ubsan_platform.h"
> >>
> >> #ifndef HWASAN_CONTAINS_UBSAN
> >> @@ -35,10 +36,31 @@
> >>
> >> typedef u8 tag_t;
> >>
> >> +#if defined(__x86_64__)
> >> +// Tags are done in middle bits using userspace aliasing.
> >> +constexpr unsigned kAddressTagShift = 39;
> >> +constexpr unsigned kTagBits = 3;
> >> +
> >> +// The alias region is placed next to the shadow so the upper bits of all
> >> +// taggable addresses matches the upper bits of the shadow base. This shift
> >> +// value determines which upper bits must match. It has a floor of 44 since the
> >> +// shadow is always 8TB.
> >> +// TODO(morehouse): In alias mode we can shrink the shadow and use a
> >> +// simpler/faster shadow calculation.
> >> +constexpr unsigned kTaggableRegionCheckShift =
> >> + __sanitizer::Max(kAddressTagShift + kTagBits + 1U, 44U);
> >> +#else
> >> // TBI (Top Byte Ignore) feature of AArch64: bits [63:56] are ignored in address
> >> // translation and can be used to store a tag.
> >> -const unsigned kAddressTagShift = 56;
> >> -const uptr kAddressTagMask = 0xFFUL << kAddressTagShift;
> >> +constexpr unsigned kAddressTagShift = 56;
> >> +constexpr unsigned kTagBits = 8;
> >> +#endif // defined(__x86_64__)
> >> +
> >> +// Mask for extracting tag bits from the lower 8 bits.
> >> +constexpr uptr kTagMask = (1UL << kTagBits) - 1;
> >> +
> >> +// Mask for extracting tag bits from full pointers.
> >> +constexpr uptr kAddressTagMask = kTagMask << kAddressTagShift;
> >>
> >> // Minimal alignment of the shadow base address. Determines the space available
> >> // for threads and stack histories. This is an ABI constant.
> >> @@ -50,7 +72,7 @@ const unsigned kRecordFPLShift = 4;
> >> const unsigned kRecordFPModulus = 1 << (64 - kRecordFPShift + kRecordFPLShift);
> >>
> >> static inline tag_t GetTagFromPointer(uptr p) {
> >> - return p >> kAddressTagShift;
> >> + return (p >> kAddressTagShift) & kTagMask;
> >> }
> >>
> >> static inline uptr UntagAddr(uptr tagged_addr) {
> >> @@ -105,15 +127,6 @@ void InstallAtExitHandler();
> >> if (hwasan_inited) \
> >> stack.Unwind(pc, bp, nullptr, common_flags()->fast_unwind_on_fatal)
> >>
> >> -#define GET_FATAL_STACK_TRACE_HERE \
> >> - GET_FATAL_STACK_TRACE_PC_BP(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME())
> >> -
> >> -#define PRINT_CURRENT_STACK_CHECK() \
> >> - { \
> >> - GET_FATAL_STACK_TRACE_HERE; \
> >> - stack.Print(); \
> >> - }
> >> -
> >> void HwasanTSDInit();
> >> void HwasanTSDThreadInit();
> >>
> >> diff --git a/libsanitizer/hwasan/hwasan_allocator.cpp b/libsanitizer/hwasan/hwasan_allocator.cpp
> >> index 0b6b7347892..a6fc794082a 100644
> >> --- a/libsanitizer/hwasan/hwasan_allocator.cpp
> >> +++ b/libsanitizer/hwasan/hwasan_allocator.cpp
> >> @@ -29,8 +29,8 @@ static AllocatorCache fallback_allocator_cache;
> >> static SpinMutex fallback_mutex;
> >> static atomic_uint8_t hwasan_allocator_tagging_enabled;
> >>
> >> -static const tag_t kFallbackAllocTag = 0xBB;
> >> -static const tag_t kFallbackFreeTag = 0xBC;
> >> +static constexpr tag_t kFallbackAllocTag = 0xBB & kTagMask;
> >> +static constexpr tag_t kFallbackFreeTag = 0xBC;
> >>
> >> enum RightAlignMode {
> >> kRightAlignNever,
> >> @@ -84,7 +84,8 @@ void HwasanAllocatorInit() {
> >> atomic_store_relaxed(&hwasan_allocator_tagging_enabled,
> >> !flags()->disable_allocator_tagging);
> >> SetAllocatorMayReturnNull(common_flags()->allocator_may_return_null);
> >> - allocator.Init(common_flags()->allocator_release_to_os_interval_ms);
> >> + allocator.Init(common_flags()->allocator_release_to_os_interval_ms,
> >> + kAliasRegionStart);
> >> for (uptr i = 0; i < sizeof(tail_magic); i++)
> >> tail_magic[i] = GetCurrentThread()->GenerateRandomTag();
> >> }
> >> @@ -148,7 +149,8 @@ static void *HwasanAllocate(StackTrace *stack, uptr orig_size, uptr alignment,
> >> // Tagging can only be skipped when both tag_in_malloc and tag_in_free are
> >> // false. When tag_in_malloc = false and tag_in_free = true malloc needs to
> >> // retag to 0.
> >> - if ((flags()->tag_in_malloc || flags()->tag_in_free) &&
> >> + if (InTaggableRegion(reinterpret_cast<uptr>(user_ptr)) &&
> >> + (flags()->tag_in_malloc || flags()->tag_in_free) &&
> >> atomic_load_relaxed(&hwasan_allocator_tagging_enabled)) {
> >> if (flags()->tag_in_malloc && malloc_bisect(stack, orig_size)) {
> >> tag_t tag = t ? t->GenerateRandomTag() : kFallbackAllocTag;
> >> @@ -175,6 +177,8 @@ static void *HwasanAllocate(StackTrace *stack, uptr orig_size, uptr alignment,
> >> static bool PointerAndMemoryTagsMatch(void *tagged_ptr) {
> >> CHECK(tagged_ptr);
> >> uptr tagged_uptr = reinterpret_cast<uptr>(tagged_ptr);
> >> + if (!InTaggableRegion(tagged_uptr))
> >> + return true;
> >> tag_t mem_tag = *reinterpret_cast<tag_t *>(
> >> MemToShadow(reinterpret_cast<uptr>(UntagPtr(tagged_ptr))));
> >> return PossiblyShortTagMatches(mem_tag, tagged_uptr, 1);
> >> @@ -187,7 +191,9 @@ static void HwasanDeallocate(StackTrace *stack, void *tagged_ptr) {
> >> if (!PointerAndMemoryTagsMatch(tagged_ptr))
> >> ReportInvalidFree(stack, reinterpret_cast<uptr>(tagged_ptr));
> >>
> >> - void *untagged_ptr = UntagPtr(tagged_ptr);
> >> + void *untagged_ptr = InTaggableRegion(reinterpret_cast<uptr>(tagged_ptr))
> >> + ? UntagPtr(tagged_ptr)
> >> + : tagged_ptr;
> >> void *aligned_ptr = reinterpret_cast<void *>(
> >> RoundDownTo(reinterpret_cast<uptr>(untagged_ptr), kShadowAlignment));
> >> Metadata *meta =
> >> @@ -219,10 +225,14 @@ static void HwasanDeallocate(StackTrace *stack, void *tagged_ptr) {
> >> Min(TaggedSize(orig_size), (uptr)flags()->max_free_fill_size);
> >> internal_memset(aligned_ptr, flags()->free_fill_byte, fill_size);
> >> }
> >> - if (flags()->tag_in_free && malloc_bisect(stack, 0) &&
> >> - atomic_load_relaxed(&hwasan_allocator_tagging_enabled))
> >> + if (InTaggableRegion(reinterpret_cast<uptr>(tagged_ptr)) &&
> >> + flags()->tag_in_free && malloc_bisect(stack, 0) &&
> >> + atomic_load_relaxed(&hwasan_allocator_tagging_enabled)) {
> >> + // Always store full 8-bit tags on free to maximize UAF detection.
> >> + tag_t tag = t ? t->GenerateRandomTag(/*num_bits=*/8) : kFallbackFreeTag;
> >> TagMemoryAligned(reinterpret_cast<uptr>(aligned_ptr), TaggedSize(orig_size),
> >> - t ? t->GenerateRandomTag() : kFallbackFreeTag);
> >> + tag);
> >> + }
> >> if (t) {
> >> allocator.Deallocate(t->allocator_cache(), aligned_ptr);
> >> if (auto *ha = t->heap_allocations())
> >> @@ -365,7 +375,7 @@ int hwasan_posix_memalign(void **memptr, uptr alignment, uptr size,
> >> // OOM error is already taken care of by HwasanAllocate.
> >> return errno_ENOMEM;
> >> CHECK(IsAligned((uptr)ptr, alignment));
> >> - *(void **)UntagPtr(memptr) = ptr;
> >> + *memptr = ptr;
> >> return 0;
> >> }
> >>
> >> diff --git a/libsanitizer/hwasan/hwasan_allocator.h b/libsanitizer/hwasan/hwasan_allocator.h
> >> index 43670a6a3fb..03bbcff3f0f 100644
> >> --- a/libsanitizer/hwasan/hwasan_allocator.h
> >> +++ b/libsanitizer/hwasan/hwasan_allocator.h
> >> @@ -13,13 +13,15 @@
> >> #ifndef HWASAN_ALLOCATOR_H
> >> #define HWASAN_ALLOCATOR_H
> >>
> >> +#include "hwasan.h"
> >> +#include "hwasan_interface_internal.h"
> >> +#include "hwasan_poisoning.h"
> >> #include "sanitizer_common/sanitizer_allocator.h"
> >> #include "sanitizer_common/sanitizer_allocator_checks.h"
> >> #include "sanitizer_common/sanitizer_allocator_interface.h"
> >> #include "sanitizer_common/sanitizer_allocator_report.h"
> >> #include "sanitizer_common/sanitizer_common.h"
> >> #include "sanitizer_common/sanitizer_ring_buffer.h"
> >> -#include "hwasan_poisoning.h"
> >>
> >> #if !defined(__aarch64__) && !defined(__x86_64__)
> >> #error Unsupported platform
> >> @@ -55,7 +57,12 @@ static const uptr kMaxAllowedMallocSize = 1UL << 40; // 1T
> >>
> >> struct AP64 {
> >> static const uptr kSpaceBeg = ~0ULL;
> >> +
> >> +#if defined(__x86_64__)
> >> + static const uptr kSpaceSize = 1ULL << kAddressTagShift;
> >> +#else
> >> static const uptr kSpaceSize = 0x2000000000ULL;
> >> +#endif
> >> static const uptr kMetadataSize = sizeof(Metadata);
> >> typedef __sanitizer::VeryDenseSizeClassMap SizeClassMap;
> >> using AddressSpaceView = LocalAddressSpaceView;
> >> @@ -102,6 +109,16 @@ typedef RingBuffer<HeapAllocationRecord> HeapAllocationsRingBuffer;
> >>
> >> void GetAllocatorStats(AllocatorStatCounters s);
> >>
> >> +inline bool InTaggableRegion(uptr addr) {
> >> +#if defined(__x86_64__)
> >> + // Aliases are mapped next to shadow so that the upper bits match the shadow
> >> + // base.
> >> + return (addr >> kTaggableRegionCheckShift) ==
> >> + (__hwasan_shadow_memory_dynamic_address >> kTaggableRegionCheckShift);
> >> +#endif
> >> + return true;
> >> +}
> >> +
> >> } // namespace __hwasan
> >>
> >> #endif // HWASAN_ALLOCATOR_H
> >> diff --git a/libsanitizer/hwasan/hwasan_checks.h b/libsanitizer/hwasan/hwasan_checks.h
> >> index a8de0fef20f..ab543ea88be 100644
> >> --- a/libsanitizer/hwasan/hwasan_checks.h
> >> +++ b/libsanitizer/hwasan/hwasan_checks.h
> >> @@ -13,6 +13,7 @@
> >> #ifndef HWASAN_CHECKS_H
> >> #define HWASAN_CHECKS_H
> >>
> >> +#include "hwasan_allocator.h"
> >> #include "hwasan_mapping.h"
> >> #include "sanitizer_common/sanitizer_common.h"
> >>
> >> @@ -81,6 +82,8 @@ enum class AccessType { Load, Store };
> >>
> >> template <ErrorAction EA, AccessType AT, unsigned LogSize>
> >> __attribute__((always_inline, nodebug)) static void CheckAddress(uptr p) {
> >> + if (!InTaggableRegion(p))
> >> + return;
> >> uptr ptr_raw = p & ~kAddressTagMask;
> >> tag_t mem_tag = *(tag_t *)MemToShadow(ptr_raw);
> >> if (UNLIKELY(!PossiblyShortTagMatches(mem_tag, p, 1 << LogSize))) {
> >> @@ -94,7 +97,7 @@ __attribute__((always_inline, nodebug)) static void CheckAddress(uptr p) {
> >> template <ErrorAction EA, AccessType AT>
> >> __attribute__((always_inline, nodebug)) static void CheckAddressSized(uptr p,
> >> uptr sz) {
> >> - if (sz == 0)
> >> + if (sz == 0 || !InTaggableRegion(p))
> >> return;
> >> tag_t ptr_tag = GetTagFromPointer(p);
> >> uptr ptr_raw = p & ~kAddressTagMask;
> >> diff --git a/libsanitizer/hwasan/hwasan_dynamic_shadow.cpp b/libsanitizer/hwasan/hwasan_dynamic_shadow.cpp
> >> index 12730b29bae..f53276e330d 100644
> >> --- a/libsanitizer/hwasan/hwasan_dynamic_shadow.cpp
> >> +++ b/libsanitizer/hwasan/hwasan_dynamic_shadow.cpp
> >> @@ -12,15 +12,17 @@
> >> ///
> >> //===----------------------------------------------------------------------===//
> >>
> >> -#include "hwasan.h"
> >> #include "hwasan_dynamic_shadow.h"
> >> -#include "hwasan_mapping.h"
> >> -#include "sanitizer_common/sanitizer_common.h"
> >> -#include "sanitizer_common/sanitizer_posix.h"
> >>
> >> #include <elf.h>
> >> #include <link.h>
> >>
> >> +#include "hwasan.h"
> >> +#include "hwasan_mapping.h"
> >> +#include "hwasan_thread_list.h"
> >> +#include "sanitizer_common/sanitizer_common.h"
> >> +#include "sanitizer_common/sanitizer_posix.h"
> >> +
> >> // The code in this file needs to run in an unrelocated binary. It should not
> >> // access any external symbol, including its own non-hidden globals.
> >>
> >> @@ -117,6 +119,12 @@ namespace __hwasan {
> >> void InitShadowGOT() {}
> >>
> >> uptr FindDynamicShadowStart(uptr shadow_size_bytes) {
> >> +#if defined(__x86_64__)
> >> + constexpr uptr kAliasSize = 1ULL << kAddressTagShift;
> >> + constexpr uptr kNumAliases = 1ULL << kTagBits;
> >> + return MapDynamicShadowAndAliases(shadow_size_bytes, kAliasSize, kNumAliases,
> >> + RingBufferSize());
> >> +#endif
> >> return MapDynamicShadow(shadow_size_bytes, kShadowScale, kShadowBaseAlignment,
> >> kHighMemEnd);
> >> }
> >> diff --git a/libsanitizer/hwasan/hwasan_flags.h b/libsanitizer/hwasan/hwasan_flags.h
> >> index 0a6998f675d..b17750158d0 100644
> >> --- a/libsanitizer/hwasan/hwasan_flags.h
> >> +++ b/libsanitizer/hwasan/hwasan_flags.h
> >> @@ -12,6 +12,8 @@
> >> #ifndef HWASAN_FLAGS_H
> >> #define HWASAN_FLAGS_H
> >>
> >> +#include "sanitizer_common/sanitizer_internal_defs.h"
> >> +
> >> namespace __hwasan {
> >>
> >> struct Flags {
> >> diff --git a/libsanitizer/hwasan/hwasan_flags.inc b/libsanitizer/hwasan/hwasan_flags.inc
> >> index 8e431d9c4ff..18ea47f981b 100644
> >> --- a/libsanitizer/hwasan/hwasan_flags.inc
> >> +++ b/libsanitizer/hwasan/hwasan_flags.inc
> >> @@ -72,3 +72,12 @@ HWASAN_FLAG(uptr, malloc_bisect_right, 0,
> >> HWASAN_FLAG(bool, malloc_bisect_dump, false,
> >> "Print all allocations within [malloc_bisect_left, "
> >> "malloc_bisect_right] range ")
> >> +
> >> +
> >> +// Exit if we fail to enable the AArch64 kernel ABI relaxation which allows
> >> +// tagged pointers in syscalls. This is the default, but being able to disable
> >> +// that behaviour is useful for running the testsuite on more platforms (the
> >> +// testsuite can run since we manually ensure any pointer arguments to syscalls
> >> +// are untagged before the call.
> >> +HWASAN_FLAG(bool, fail_without_syscall_abi, true,
> >> + "Exit if fail to request relaxed syscall ABI.")
> >> diff --git a/libsanitizer/hwasan/hwasan_interceptors.cpp b/libsanitizer/hwasan/hwasan_interceptors.cpp
> >> index 44e569ee6d7..ad67e2787d3 100644
> >> --- a/libsanitizer/hwasan/hwasan_interceptors.cpp
> >> +++ b/libsanitizer/hwasan/hwasan_interceptors.cpp
> >> @@ -221,8 +221,7 @@ INTERCEPTOR(int, pthread_create, void *th, void *attr, void *(*callback)(void*),
> >> ThreadStartArg *A = reinterpret_cast<ThreadStartArg *> (MmapOrDie(
> >> GetPageSizeCached(), "pthread_create"));
> >> *A = {callback, param};
> >> - int res = REAL(pthread_create)(UntagPtr(th), UntagPtr(attr),
> >> - &HwasanThreadStartFunc, A);
> >> + int res = REAL(pthread_create)(th, attr, &HwasanThreadStartFunc, A);
> >> return res;
> >> }
> >>
> >> diff --git a/libsanitizer/hwasan/hwasan_interceptors_vfork.S b/libsanitizer/hwasan/hwasan_interceptors_vfork.S
> >> index 23d565936d8..fd20825e3da 100644
> >> --- a/libsanitizer/hwasan/hwasan_interceptors_vfork.S
> >> +++ b/libsanitizer/hwasan/hwasan_interceptors_vfork.S
> >> @@ -1,4 +1,5 @@
> >> #include "sanitizer_common/sanitizer_asm.h"
> >> +#include "builtins/assembly.h"
> >>
> >> #if defined(__linux__) && HWASAN_WITH_INTERCEPTORS
> >> #define COMMON_INTERCEPTOR_SPILL_AREA __hwasan_extra_spill_area
> >> @@ -9,3 +10,5 @@
> >> #endif
> >>
> >> NO_EXEC_STACK_DIRECTIVE
> >> +
> >> +GNU_PROPERTY_BTI_PAC
> >> diff --git a/libsanitizer/hwasan/hwasan_interface_internal.h b/libsanitizer/hwasan/hwasan_interface_internal.h
> >> index aedda317497..25c0f94fe51 100644
> >> --- a/libsanitizer/hwasan/hwasan_interface_internal.h
> >> +++ b/libsanitizer/hwasan/hwasan_interface_internal.h
> >> @@ -222,6 +222,9 @@ SANITIZER_INTERFACE_ATTRIBUTE
> >> void *__hwasan_memset(void *s, int c, uptr n);
> >> SANITIZER_INTERFACE_ATTRIBUTE
> >> void *__hwasan_memmove(void *dest, const void *src, uptr n);
> >> +
> >> +SANITIZER_INTERFACE_ATTRIBUTE
> >> +void __hwasan_set_error_report_callback(void (*callback)(const char *));
> >> } // extern "C"
> >>
> >> #endif // HWASAN_INTERFACE_INTERNAL_H
> >> diff --git a/libsanitizer/hwasan/hwasan_linux.cpp b/libsanitizer/hwasan/hwasan_linux.cpp
> >> index e99926d355c..8ce0ff7da95 100644
> >> --- a/libsanitizer/hwasan/hwasan_linux.cpp
> >> +++ b/libsanitizer/hwasan/hwasan_linux.cpp
> >> @@ -76,6 +76,8 @@ uptr kHighShadowEnd;
> >> uptr kHighMemStart;
> >> uptr kHighMemEnd;
> >>
> >> +uptr kAliasRegionStart; // Always 0 on non-x86.
> >> +
> >> static void PrintRange(uptr start, uptr end, const char *name) {
> >> Printf("|| [%p, %p] || %.*s ||\n", (void *)start, (void *)end, 10, name);
> >> }
> >> @@ -119,9 +121,11 @@ void InitPrctl() {
> >> #define PR_GET_TAGGED_ADDR_CTRL 56
> >> #define PR_TAGGED_ADDR_ENABLE (1UL << 0)
> >> // Check we're running on a kernel that can use the tagged address ABI.
> >> - if (internal_prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0) == (uptr)-1 &&
> >> - errno == EINVAL) {
> >> -#if SANITIZER_ANDROID
> >> + int local_errno = 0;
> >> + if (internal_iserror(internal_prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0),
> >> + &local_errno) &&
> >> + local_errno == EINVAL) {
> >> +#if SANITIZER_ANDROID || defined(__x86_64__)
> >> // Some older Android kernels have the tagged pointer ABI on
> >> // unconditionally, and hence don't have the tagged-addr prctl while still
> >> // allow the ABI.
> >> @@ -129,17 +133,20 @@ void InitPrctl() {
> >> // case.
> >> return;
> >> #else
> >> - Printf(
> >> - "FATAL: "
> >> - "HWAddressSanitizer requires a kernel with tagged address ABI.\n");
> >> - Die();
> >> + if (flags()->fail_without_syscall_abi) {
> >> + Printf(
> >> + "FATAL: "
> >> + "HWAddressSanitizer requires a kernel with tagged address ABI.\n");
> >> + Die();
> >> + }
> >> #endif
> >> }
> >>
> >> // Turn on the tagged address ABI.
> >> - if (internal_prctl(PR_SET_TAGGED_ADDR_CTRL, PR_TAGGED_ADDR_ENABLE, 0, 0, 0) ==
> >> - (uptr)-1 ||
> >> - !internal_prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0)) {
> >> + if ((internal_iserror(internal_prctl(PR_SET_TAGGED_ADDR_CTRL,
> >> + PR_TAGGED_ADDR_ENABLE, 0, 0, 0)) ||
> >> + !internal_prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0)) &&
> >> + flags()->fail_without_syscall_abi) {
> >> Printf(
> >> "FATAL: HWAddressSanitizer failed to enable tagged address syscall "
> >> "ABI.\nSuggest check `sysctl abi.tagged_addr_disabled` "
> >> @@ -174,6 +181,18 @@ bool InitShadow() {
> >> // High memory starts where allocated shadow allows.
> >> kHighMemStart = ShadowToMem(kHighShadowStart);
> >>
> >> +#if defined(__x86_64__)
> >> + constexpr uptr kAliasRegionOffset = 1ULL << (kTaggableRegionCheckShift - 1);
> >> + kAliasRegionStart =
> >> + __hwasan_shadow_memory_dynamic_address + kAliasRegionOffset;
> >> +
> >> + CHECK_EQ(kAliasRegionStart >> kTaggableRegionCheckShift,
> >> + __hwasan_shadow_memory_dynamic_address >> kTaggableRegionCheckShift);
> >> + CHECK_EQ(
> >> + (kAliasRegionStart + kAliasRegionOffset - 1) >> kTaggableRegionCheckShift,
> >> + __hwasan_shadow_memory_dynamic_address >> kTaggableRegionCheckShift);
> >> +#endif
> >> +
> >> // Check the sanity of the defined memory ranges (there might be gaps).
> >> CHECK_EQ(kHighMemStart % GetMmapGranularity(), 0);
> >> CHECK_GT(kHighMemStart, kHighShadowEnd);
> >> @@ -217,7 +236,9 @@ void InitThreads() {
> >> }
> >>
> >> bool MemIsApp(uptr p) {
> >> +#if !defined(__x86_64__) // Memory outside the alias range has non-zero tags.
> >> CHECK(GetTagFromPointer(p) == 0);
> >> +#endif
> >> return p >= kHighMemStart || (p >= kLowMemStart && p <= kLowMemEnd);
> >> }
> >>
> >> diff --git a/libsanitizer/hwasan/hwasan_mapping.h b/libsanitizer/hwasan/hwasan_mapping.h
> >> index c149687bdfa..8243d1ec7ed 100644
> >> --- a/libsanitizer/hwasan/hwasan_mapping.h
> >> +++ b/libsanitizer/hwasan/hwasan_mapping.h
> >> @@ -48,6 +48,8 @@ extern uptr kHighShadowEnd;
> >> extern uptr kHighMemStart;
> >> extern uptr kHighMemEnd;
> >>
> >> +extern uptr kAliasRegionStart;
> >> +
> >> inline uptr MemToShadow(uptr untagged_addr) {
> >> return (untagged_addr >> kShadowScale) +
> >> __hwasan_shadow_memory_dynamic_address;
> >> diff --git a/libsanitizer/hwasan/hwasan_memintrinsics.cpp b/libsanitizer/hwasan/hwasan_memintrinsics.cpp
> >> index e82d77a1bc1..fab017aae60 100644
> >> --- a/libsanitizer/hwasan/hwasan_memintrinsics.cpp
> >> +++ b/libsanitizer/hwasan/hwasan_memintrinsics.cpp
> >> @@ -24,7 +24,7 @@ using namespace __hwasan;
> >> void *__hwasan_memset(void *block, int c, uptr size) {
> >> CheckAddressSized<ErrorAction::Recover, AccessType::Store>(
> >> reinterpret_cast<uptr>(block), size);
> >> - return memset(UntagPtr(block), c, size);
> >> + return memset(block, c, size);
> >> }
> >>
> >> void *__hwasan_memcpy(void *to, const void *from, uptr size) {
> >> @@ -32,7 +32,7 @@ void *__hwasan_memcpy(void *to, const void *from, uptr size) {
> >> reinterpret_cast<uptr>(to), size);
> >> CheckAddressSized<ErrorAction::Recover, AccessType::Load>(
> >> reinterpret_cast<uptr>(from), size);
> >> - return memcpy(UntagPtr(to), UntagPtr(from), size);
> >> + return memcpy(to, from, size);
> >> }
> >>
> >> void *__hwasan_memmove(void *to, const void *from, uptr size) {
> >> diff --git a/libsanitizer/hwasan/hwasan_new_delete.cpp b/libsanitizer/hwasan/hwasan_new_delete.cpp
> >> index 8d01d3944f2..69cddda736e 100644
> >> --- a/libsanitizer/hwasan/hwasan_new_delete.cpp
> >> +++ b/libsanitizer/hwasan/hwasan_new_delete.cpp
> >> @@ -27,6 +27,12 @@
> >> void *res = hwasan_malloc(size, &stack);\
> >> if (!nothrow && UNLIKELY(!res)) ReportOutOfMemory(size, &stack);\
> >> return res
> >> +#define OPERATOR_NEW_ALIGN_BODY(nothrow) \
> >> + GET_MALLOC_STACK_TRACE; \
> >> + void *res = hwasan_aligned_alloc(static_cast<uptr>(align), size, &stack); \
> >> + if (!nothrow && UNLIKELY(!res)) \
> >> + ReportOutOfMemory(size, &stack); \
> >> + return res
> >>
> >> #define OPERATOR_DELETE_BODY \
> >> GET_MALLOC_STACK_TRACE; \
> >> @@ -50,6 +56,7 @@ using namespace __hwasan;
> >> // Fake std::nothrow_t to avoid including <new>.
> >> namespace std {
> >> struct nothrow_t {};
> >> + enum class align_val_t : size_t {};
> >> } // namespace std
> >>
> >>
> >> @@ -66,6 +73,22 @@ INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
> >> void *operator new[](size_t size, std::nothrow_t const&) {
> >> OPERATOR_NEW_BODY(true /*nothrow*/);
> >> }
> >> +INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void *operator new(
> >> + size_t size, std::align_val_t align) {
> >> + OPERATOR_NEW_ALIGN_BODY(false /*nothrow*/);
> >> +}
> >> +INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void *operator new[](
> >> + size_t size, std::align_val_t align) {
> >> + OPERATOR_NEW_ALIGN_BODY(false /*nothrow*/);
> >> +}
> >> +INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void *operator new(
> >> + size_t size, std::align_val_t align, std::nothrow_t const &) {
> >> + OPERATOR_NEW_ALIGN_BODY(true /*nothrow*/);
> >> +}
> >> +INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void *operator new[](
> >> + size_t size, std::align_val_t align, std::nothrow_t const &) {
> >> + OPERATOR_NEW_ALIGN_BODY(true /*nothrow*/);
> >> +}
> >>
> >> INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
> >> void operator delete(void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY; }
> >> @@ -77,5 +100,21 @@ INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
> >> void operator delete[](void *ptr, std::nothrow_t const&) {
> >> OPERATOR_DELETE_BODY;
> >> }
> >> +INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void operator delete(
> >> + void *ptr, std::align_val_t align) NOEXCEPT {
> >> + OPERATOR_DELETE_BODY;
> >> +}
> >> +INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void operator delete[](
> >> + void *ptr, std::align_val_t) NOEXCEPT {
> >> + OPERATOR_DELETE_BODY;
> >> +}
> >> +INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void operator delete(
> >> + void *ptr, std::align_val_t, std::nothrow_t const &) NOEXCEPT {
> >> + OPERATOR_DELETE_BODY;
> >> +}
> >> +INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void operator delete[](
> >> + void *ptr, std::align_val_t, std::nothrow_t const &) NOEXCEPT {
> >> + OPERATOR_DELETE_BODY;
> >> +}
> >>
> >> #endif // OPERATOR_NEW_BODY
> >> diff --git a/libsanitizer/hwasan/hwasan_report.cpp b/libsanitizer/hwasan/hwasan_report.cpp
> >> index 894a149775f..c0217799391 100644
> >> --- a/libsanitizer/hwasan/hwasan_report.cpp
> >> +++ b/libsanitizer/hwasan/hwasan_report.cpp
> >> @@ -43,12 +43,16 @@ class ScopedReport {
> >> }
> >>
> >> ~ScopedReport() {
> >> + void (*report_cb)(const char *);
> >> {
> >> BlockingMutexLock lock(&error_message_lock_);
> >> - if (fatal)
> >> - SetAbortMessage(error_message_.data());
> >> + report_cb = error_report_callback_;
> >> error_message_ptr_ = nullptr;
> >> }
> >> + if (report_cb)
> >> + report_cb(error_message_.data());
> >> + if (fatal)
> >> + SetAbortMessage(error_message_.data());
> >> if (common_flags()->print_module_map >= 2 ||
> >> (fatal && common_flags()->print_module_map))
> >> DumpProcessMap();
> >> @@ -66,6 +70,12 @@ class ScopedReport {
> >> // overwrite old trailing '\0', keep new trailing '\0' untouched.
> >> internal_memcpy(&(*error_message_ptr_)[old_size - 1], msg, len);
> >> }
> >> +
> >> + static void SetErrorReportCallback(void (*callback)(const char *)) {
> >> + BlockingMutexLock lock(&error_message_lock_);
> >> + error_report_callback_ = callback;
> >> + }
> >> +
> >> private:
> >> ScopedErrorReportLock error_report_lock_;
> >> InternalMmapVector<char> error_message_;
> >> @@ -73,10 +83,12 @@ class ScopedReport {
> >>
> >> static InternalMmapVector<char> *error_message_ptr_;
> >> static BlockingMutex error_message_lock_;
> >> + static void (*error_report_callback_)(const char *);
> >> };
> >>
> >> InternalMmapVector<char> *ScopedReport::error_message_ptr_;
> >> BlockingMutex ScopedReport::error_message_lock_;
> >> +void (*ScopedReport::error_report_callback_)(const char *);
> >>
> >> // If there is an active ScopedReport, append to its error message.
> >> void AppendToErrorMessageBuffer(const char *buffer) {
> >> @@ -212,7 +224,7 @@ static void PrintStackAllocations(StackAllocationsRingBuffer *sa,
> >>
> >> // We didn't find any locals. Most likely we don't have symbols, so dump
> >> // the information that we have for offline analysis.
> >> - InternalScopedString frame_desc(GetPageSizeCached() * 2);
> >> + InternalScopedString frame_desc;
> >> Printf("Previously allocated frames:\n");
> >> for (uptr i = 0; i < frames; i++) {
> >> const uptr *record_addr = &(*sa)[i];
> >> @@ -447,7 +459,7 @@ static void PrintTagInfoAroundAddr(tag_t *tag_ptr, uptr num_rows,
> >> RoundDownTo(reinterpret_cast<uptr>(tag_ptr), row_len));
> >> tag_t *beg_row = center_row_beg - row_len * (num_rows / 2);
> >> tag_t *end_row = center_row_beg + row_len * ((num_rows + 1) / 2);
> >> - InternalScopedString s(GetPageSizeCached() * 8);
> >> + InternalScopedString s;
> >> for (tag_t *row = beg_row; row < end_row; row += row_len) {
> >> s.append("%s", row == center_row_beg ? "=>" : " ");
> >> s.append("%p:", row);
> >> @@ -535,7 +547,7 @@ void ReportTailOverwritten(StackTrace *stack, uptr tagged_addr, uptr orig_size,
> >> GetStackTraceFromId(chunk.GetAllocStackId()).Print();
> >> }
> >>
> >> - InternalScopedString s(GetPageSizeCached() * 8);
> >> + InternalScopedString s;
> >> CHECK_GT(tail_size, 0U);
> >> CHECK_LT(tail_size, kShadowAlignment);
> >> u8 *tail = reinterpret_cast<u8*>(untagged_addr + orig_size);
> >> @@ -650,3 +662,7 @@ void ReportRegisters(uptr *frame, uptr pc) {
> >> }
> >>
> >> } // namespace __hwasan
> >> +
> >> +void __hwasan_set_error_report_callback(void (*callback)(const char *)) {
> >> + __hwasan::ScopedReport::SetErrorReportCallback(callback);
> >> +}
> >> diff --git a/libsanitizer/hwasan/hwasan_setjmp.S b/libsanitizer/hwasan/hwasan_setjmp.S
> >> index 0c135433194..381af63363c 100644
> >> --- a/libsanitizer/hwasan/hwasan_setjmp.S
> >> +++ b/libsanitizer/hwasan/hwasan_setjmp.S
> >> @@ -12,6 +12,7 @@
> >> //===----------------------------------------------------------------------===//
> >>
> >> #include "sanitizer_common/sanitizer_asm.h"
> >> +#include "builtins/assembly.h"
> >>
> >> #if HWASAN_WITH_INTERCEPTORS && defined(__aarch64__)
> >> #include "sanitizer_common/sanitizer_platform.h"
> >> @@ -34,6 +35,7 @@
> >> ASM_TYPE_FUNCTION(__interceptor_setjmp)
> >> __interceptor_setjmp:
> >> CFI_STARTPROC
> >> + BTI_C
> >> mov x1, #0
> >> b __interceptor_sigsetjmp
> >> CFI_ENDPROC
> >> @@ -46,6 +48,7 @@ ASM_SIZE(__interceptor_setjmp)
> >> ASM_TYPE_FUNCTION(__interceptor_setjmp_bionic)
> >> __interceptor_setjmp_bionic:
> >> CFI_STARTPROC
> >> + BTI_C
> >> mov x1, #1
> >> b __interceptor_sigsetjmp
> >> CFI_ENDPROC
> >> @@ -56,6 +59,7 @@ ASM_SIZE(__interceptor_setjmp_bionic)
> >> ASM_TYPE_FUNCTION(__interceptor_sigsetjmp)
> >> __interceptor_sigsetjmp:
> >> CFI_STARTPROC
> >> + BTI_C
> >> stp x19, x20, [x0, #0<<3]
> >> stp x21, x22, [x0, #2<<3]
> >> stp x23, x24, [x0, #4<<3]
> >> @@ -98,3 +102,5 @@ ALIAS __interceptor_setjmp, _setjmp
> >>
> >> // We do not need executable stack.
> >> NO_EXEC_STACK_DIRECTIVE
> >> +
> >> +GNU_PROPERTY_BTI_PAC
> >> diff --git a/libsanitizer/hwasan/hwasan_tag_mismatch_aarch64.S b/libsanitizer/hwasan/hwasan_tag_mismatch_aarch64.S
> >> index 08df12736bb..bcb0df42019 100644
> >> --- a/libsanitizer/hwasan/hwasan_tag_mismatch_aarch64.S
> >> +++ b/libsanitizer/hwasan/hwasan_tag_mismatch_aarch64.S
> >> @@ -1,4 +1,5 @@
> >> #include "sanitizer_common/sanitizer_asm.h"
> >> +#include "builtins/assembly.h"
> >>
> >> // The content of this file is AArch64-only:
> >> #if defined(__aarch64__)
> >> @@ -74,6 +75,8 @@
> >> .global __hwasan_tag_mismatch
> >> .type __hwasan_tag_mismatch, %function
> >> __hwasan_tag_mismatch:
> >> + BTI_J
> >> +
> >> // Compute the granule position one past the end of the access.
> >> mov x16, #1
> >> and x17, x1, #0xf
> >> @@ -106,6 +109,7 @@ __hwasan_tag_mismatch:
> >> .type __hwasan_tag_mismatch_v2, %function
> >> __hwasan_tag_mismatch_v2:
> >> CFI_STARTPROC
> >> + BTI_J
> >>
> >> // Set the CFA to be the return address for caller of __hwasan_check_*. Note
> >> // that we do not emit CFI predicates to describe the contents of this stack
> >> @@ -150,3 +154,5 @@ __hwasan_tag_mismatch_v2:
> >>
> >> // We do not need executable stack.
> >> NO_EXEC_STACK_DIRECTIVE
> >> +
> >> +GNU_PROPERTY_BTI_PAC
> >> diff --git a/libsanitizer/hwasan/hwasan_thread.cpp b/libsanitizer/hwasan/hwasan_thread.cpp
> >> index b81a6350c05..bb4d56abed0 100644
> >> --- a/libsanitizer/hwasan/hwasan_thread.cpp
> >> +++ b/libsanitizer/hwasan/hwasan_thread.cpp
> >> @@ -35,6 +35,10 @@ void Thread::InitRandomState() {
> >> }
> >>
> >> void Thread::Init(uptr stack_buffer_start, uptr stack_buffer_size) {
> >> + CHECK_EQ(0, unique_id_); // try to catch bad stack reuse
> >> + CHECK_EQ(0, stack_top_);
> >> + CHECK_EQ(0, stack_bottom_);
> >> +
> >> static u64 unique_id;
> >> unique_id_ = unique_id++;
> >> if (auto sz = flags()->heap_history_size)
> >> @@ -113,18 +117,21 @@ static u32 xorshift(u32 state) {
> >> }
> >>
> >> // Generate a (pseudo-)random non-zero tag.
> >> -tag_t Thread::GenerateRandomTag() {
> >> +tag_t Thread::GenerateRandomTag(uptr num_bits) {
> >> + DCHECK_GT(num_bits, 0);
> >> if (tagging_disabled_) return 0;
> >> tag_t tag;
> >> + const uptr tag_mask = (1ULL << num_bits) - 1;
> >> do {
> >> if (flags()->random_tags) {
> >> if (!random_buffer_)
> >> random_buffer_ = random_state_ = xorshift(random_state_);
> >> CHECK(random_buffer_);
> >> - tag = random_buffer_ & 0xFF;
> >> - random_buffer_ >>= 8;
> >> + tag = random_buffer_ & tag_mask;
> >> + random_buffer_ >>= num_bits;
> >> } else {
> >> - tag = random_state_ = (random_state_ + 1) & 0xFF;
> >> + random_state_ += 1;
> >> + tag = random_state_ & tag_mask;
> >> }
> >> } while (!tag);
> >> return tag;
> >> diff --git a/libsanitizer/hwasan/hwasan_thread.h b/libsanitizer/hwasan/hwasan_thread.h
> >> index ebcdb791fb3..1c71cab41c4 100644
> >> --- a/libsanitizer/hwasan/hwasan_thread.h
> >> +++ b/libsanitizer/hwasan/hwasan_thread.h
> >> @@ -42,7 +42,7 @@ class Thread {
> >> HeapAllocationsRingBuffer *heap_allocations() { return heap_allocations_; }
> >> StackAllocationsRingBuffer *stack_allocations() { return stack_allocations_; }
> >>
> >> - tag_t GenerateRandomTag();
> >> + tag_t GenerateRandomTag(uptr num_bits = kTagBits);
> >>
> >> void DisableTagging() { tagging_disabled_++; }
> >> void EnableTagging() { tagging_disabled_--; }
> >> @@ -74,8 +74,6 @@ class Thread {
> >> HeapAllocationsRingBuffer *heap_allocations_;
> >> StackAllocationsRingBuffer *stack_allocations_;
> >>
> >> - Thread *next_; // All live threads form a linked list.
> >> -
> >> u64 unique_id_; // counting from zero.
> >>
> >> u32 tagging_disabled_; // if non-zero, malloc uses zero tag in this thread.
> >> diff --git a/libsanitizer/hwasan/hwasan_thread_list.h b/libsanitizer/hwasan/hwasan_thread_list.h
> >> index 914b632d977..11c586314ce 100644
> >> --- a/libsanitizer/hwasan/hwasan_thread_list.h
> >> +++ b/libsanitizer/hwasan/hwasan_thread_list.h
> >> @@ -66,40 +66,6 @@ static uptr RingBufferSize() {
> >> return 0;
> >> }
> >>
> >> -struct ThreadListHead {
> >> - Thread *list_;
> >> -
> >> - ThreadListHead() : list_(nullptr) {}
> >> -
> >> - void Push(Thread *t) {
> >> - t->next_ = list_;
> >> - list_ = t;
> >> - }
> >> -
> >> - Thread *Pop() {
> >> - Thread *t = list_;
> >> - if (t)
> >> - list_ = t->next_;
> >> - return t;
> >> - }
> >> -
> >> - void Remove(Thread *t) {
> >> - Thread **cur = &list_;
> >> - while (*cur != t) cur = &(*cur)->next_;
> >> - CHECK(*cur && "thread not found");
> >> - *cur = (*cur)->next_;
> >> - }
> >> -
> >> - template <class CB>
> >> - void ForEach(CB cb) {
> >> - Thread *t = list_;
> >> - while (t) {
> >> - cb(t);
> >> - t = t->next_;
> >> - }
> >> - }
> >> -};
> >> -
> >> struct ThreadStats {
> >> uptr n_live_threads;
> >> uptr total_stack_size;
> >> @@ -120,17 +86,23 @@ class HwasanThreadList {
> >> }
> >>
> >> Thread *CreateCurrentThread() {
> >> - Thread *t;
> >> + Thread *t = nullptr;
> >> {
> >> - SpinMutexLock l(&list_mutex_);
> >> - t = free_list_.Pop();
> >> - if (t) {
> >> - uptr start = (uptr)t - ring_buffer_size_;
> >> - internal_memset((void *)start, 0, ring_buffer_size_ + sizeof(Thread));
> >> - } else {
> >> - t = AllocThread();
> >> + SpinMutexLock l(&free_list_mutex_);
> >> + if (!free_list_.empty()) {
> >> + t = free_list_.back();
> >> + free_list_.pop_back();
> >> }
> >> - live_list_.Push(t);
> >> + }
> >> + if (t) {
> >> + uptr start = (uptr)t - ring_buffer_size_;
> >> + internal_memset((void *)start, 0, ring_buffer_size_ + sizeof(Thread));
> >> + } else {
> >> + t = AllocThread();
> >> + }
> >> + {
> >> + SpinMutexLock l(&live_list_mutex_);
> >> + live_list_.push_back(t);
> >> }
> >> t->Init((uptr)t - ring_buffer_size_, ring_buffer_size_);
> >> AddThreadStats(t);
> >> @@ -142,13 +114,26 @@ class HwasanThreadList {
> >> ReleaseMemoryPagesToOS(start, start + thread_alloc_size_);
> >> }
> >>
> >> + void RemoveThreadFromLiveList(Thread *t) {
> >> + SpinMutexLock l(&live_list_mutex_);
> >> + for (Thread *&t2 : live_list_)
> >> + if (t2 == t) {
> >> + // To remove t2, copy the last element of the list in t2's position, and
> >> + // pop_back(). This works even if t2 is itself the last element.
> >> + t2 = live_list_.back();
> >> + live_list_.pop_back();
> >> + return;
> >> + }
> >> + CHECK(0 && "thread not found in live list");
> >> + }
> >> +
> >> void ReleaseThread(Thread *t) {
> >> RemoveThreadStats(t);
> >> t->Destroy();
> >> - SpinMutexLock l(&list_mutex_);
> >> - live_list_.Remove(t);
> >> - free_list_.Push(t);
> >> DontNeedThread(t);
> >> + RemoveThreadFromLiveList(t);
> >> + SpinMutexLock l(&free_list_mutex_);
> >> + free_list_.push_back(t);
> >> }
> >>
> >> Thread *GetThreadByBufferAddress(uptr p) {
> >> @@ -165,8 +150,8 @@ class HwasanThreadList {
> >>
> >> template <class CB>
> >> void VisitAllLiveThreads(CB cb) {
> >> - SpinMutexLock l(&list_mutex_);
> >> - live_list_.ForEach(cb);
> >> + SpinMutexLock l(&live_list_mutex_);
> >> + for (Thread *t : live_list_) cb(t);
> >> }
> >>
> >> void AddThreadStats(Thread *t) {
> >> @@ -188,6 +173,7 @@ class HwasanThreadList {
> >>
> >> private:
> >> Thread *AllocThread() {
> >> + SpinMutexLock l(&free_space_mutex_);
> >> uptr align = ring_buffer_size_ * 2;
> >> CHECK(IsAligned(free_space_, align));
> >> Thread *t = (Thread *)(free_space_ + ring_buffer_size_);
> >> @@ -196,14 +182,16 @@ class HwasanThreadList {
> >> return t;
> >> }
> >>
> >> + SpinMutex free_space_mutex_;
> >> uptr free_space_;
> >> uptr free_space_end_;
> >> uptr ring_buffer_size_;
> >> uptr thread_alloc_size_;
> >>
> >> - ThreadListHead free_list_;
> >> - ThreadListHead live_list_;
> >> - SpinMutex list_mutex_;
> >> + SpinMutex free_list_mutex_;
> >> + InternalMmapVector<Thread *> free_list_;
> >> + SpinMutex live_list_mutex_;
> >> + InternalMmapVector<Thread *> live_list_;
> >>
> >> ThreadStats stats_;
> >> SpinMutex stats_mutex_;
> >> diff --git a/libsanitizer/include/sanitizer/common_interface_defs.h b/libsanitizer/include/sanitizer/common_interface_defs.h
> >> index b4f977bf557..cd69285b8d4 100644
> >> --- a/libsanitizer/include/sanitizer/common_interface_defs.h
> >> +++ b/libsanitizer/include/sanitizer/common_interface_defs.h
> >> @@ -43,6 +43,9 @@ void __sanitizer_set_report_path(const char *path);
> >> // Tell the tools to write their reports to the provided file descriptor
> >> // (casted to void *).
> >> void __sanitizer_set_report_fd(void *fd);
> >> +// Get the current full report file path, if a path was specified by
> >> +// an earlier call to __sanitizer_set_report_path. Returns null otherwise.
> >> +const char *__sanitizer_get_report_path();
> >>
> >> // 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
> >> diff --git a/libsanitizer/include/sanitizer/dfsan_interface.h b/libsanitizer/include/sanitizer/dfsan_interface.h
> >> index 18b2c81a602..40f9379b557 100644
> >> --- a/libsanitizer/include/sanitizer/dfsan_interface.h
> >> +++ b/libsanitizer/include/sanitizer/dfsan_interface.h
> >> @@ -22,6 +22,7 @@ extern "C" {
> >> #endif
> >>
> >> typedef uint16_t dfsan_label;
> >> +typedef uint32_t dfsan_origin;
> >>
> >> /// Stores information associated with a specific label identifier. A label
> >> /// may be a base label created using dfsan_create_label, with associated
> >> @@ -63,6 +64,12 @@ void dfsan_add_label(dfsan_label label, void *addr, size_t size);
> >> /// value.
> >> dfsan_label dfsan_get_label(long data);
> >>
> >> +/// Retrieves the immediate origin associated with the given data. The returned
> >> +/// origin may point to another origin.
> >> +///
> >> +/// The type of 'data' is arbitrary.
> >> +dfsan_origin dfsan_get_origin(long data);
> >> +
> >> /// Retrieves the label associated with the data at the given address.
> >> dfsan_label dfsan_read_label(const void *addr, size_t size);
> >>
> >> @@ -110,6 +117,15 @@ void dfsan_weak_hook_memcmp(void *caller_pc, const void *s1, const void *s2,
> >> void dfsan_weak_hook_strncmp(void *caller_pc, const char *s1, const char *s2,
> >> size_t n, dfsan_label s1_label,
> >> dfsan_label s2_label, dfsan_label n_label);
> >> +
> >> +/// Prints the origin trace of the label at the address addr to stderr. It also
> >> +/// prints description at the beginning of the trace. If origin tracking is not
> >> +/// on, or the address is not labeled, it prints nothing.
> >> +void dfsan_print_origin_trace(const void *addr, const char *description);
> >> +
> >> +/// Retrieves the very first origin associated with the data at the given
> >> +/// address.
> >> +dfsan_origin dfsan_get_init_origin(const void *addr);
> >> #ifdef __cplusplus
> >> } // extern "C"
> >>
> >> diff --git a/libsanitizer/include/sanitizer/hwasan_interface.h b/libsanitizer/include/sanitizer/hwasan_interface.h
> >> index 4c9ad13aa0c..14035c05c63 100644
> >> --- a/libsanitizer/include/sanitizer/hwasan_interface.h
> >> +++ b/libsanitizer/include/sanitizer/hwasan_interface.h
> >> @@ -73,6 +73,9 @@ extern "C" {
> >> * accessed through the pointer in x, or -1 if the whole range is good. */
> >> intptr_t __hwasan_test_shadow(const volatile void *x, size_t size);
> >>
> >> + /* Sets the callback function to be called during HWASan error reporting. */
> >> + void __hwasan_set_error_report_callback(void (*callback)(const char *));
> >> +
> >> int __sanitizer_posix_memalign(void **memptr, size_t alignment, size_t size);
> >> void * __sanitizer_memalign(size_t alignment, size_t size);
> >> void * __sanitizer_aligned_alloc(size_t alignment, size_t size);
> >> diff --git a/libsanitizer/include/sanitizer/memprof_interface.h b/libsanitizer/include/sanitizer/memprof_interface.h
> >> index a7212605100..76031de4014 100644
> >> --- a/libsanitizer/include/sanitizer/memprof_interface.h
> >> +++ b/libsanitizer/include/sanitizer/memprof_interface.h
> >> @@ -53,6 +53,11 @@ void __memprof_print_accumulated_stats(void);
> >> /// \returns Default options string.
> >> const char *__memprof_default_options(void);
> >>
> >> +/// Prints the memory profile to the current profile file.
> >> +///
> >> +/// \returns 0 on success.
> >> +int __memprof_profile_dump(void);
> >> +
> >> #ifdef __cplusplus
> >> } // extern "C"
> >> #endif
> >> diff --git a/libsanitizer/include/sanitizer/tsan_interface.h b/libsanitizer/include/sanitizer/tsan_interface.h
> >> index 96b8ad58541..565aa391a9f 100644
> >> --- a/libsanitizer/include/sanitizer/tsan_interface.h
> >> +++ b/libsanitizer/include/sanitizer/tsan_interface.h
> >> @@ -67,6 +67,12 @@ static const unsigned __tsan_mutex_recursive_lock = 1 << 6;
> >> // the corresponding __tsan_mutex_post_lock annotation.
> >> static const unsigned __tsan_mutex_recursive_unlock = 1 << 7;
> >>
> >> +// Convenient composed constants.
> >> +static const unsigned __tsan_mutex_try_read_lock =
> >> + __tsan_mutex_read_lock | __tsan_mutex_try_lock;
> >> +static const unsigned __tsan_mutex_try_read_lock_failed =
> >> + __tsan_mutex_try_read_lock | __tsan_mutex_try_lock_failed;
> >> +
> >> // Annotate creation of a mutex.
> >> // Supported flags: mutex creation flags.
> >> void __tsan_mutex_create(void *addr, unsigned flags);
> >> @@ -141,7 +147,7 @@ void __tsan_external_write(void *addr, void *caller_pc, void *tag);
> >> // and freed by __tsan_destroy_fiber.
> >> // - TSAN context of current fiber or thread can be obtained
> >> // by calling __tsan_get_current_fiber.
> >> -// - __tsan_switch_to_fiber should be called immediatly before switch
> >> +// - __tsan_switch_to_fiber should be called immediately before switch
> >> // to fiber, such as call of swapcontext.
> >> // - Fiber name can be set by __tsan_set_fiber_name.
> >> void *__tsan_get_current_fiber(void);
> >> @@ -154,6 +160,15 @@ void __tsan_set_fiber_name(void *fiber, const char *name);
> >> // Do not establish a happens-before relation between fibers
> >> static const unsigned __tsan_switch_to_fiber_no_sync = 1 << 0;
> >>
> >> +// User-provided callback invoked on TSan initialization.
> >> +void __tsan_on_initialize();
> >> +
> >> +// User-provided callback invoked on TSan shutdown.
> >> +// `failed` - Nonzero if TSan did detect issues, zero otherwise.
> >> +// Return `0` if TSan should exit as if no issues were detected. Return nonzero
> >> +// if TSan should exit as if issues were detected.
> >> +int __tsan_on_finalize(int failed);
> >> +
> >> #ifdef __cplusplus
> >> } // extern "C"
> >> #endif
> >> diff --git a/libsanitizer/include/sanitizer/tsan_interface_atomic.h b/libsanitizer/include/sanitizer/tsan_interface_atomic.h
> >> index 8052bc1d56b..5e41e2256c3 100644
> >> --- a/libsanitizer/include/sanitizer/tsan_interface_atomic.h
> >> +++ b/libsanitizer/include/sanitizer/tsan_interface_atomic.h
> >> @@ -30,7 +30,7 @@ __extension__ typedef __int128 __tsan_atomic128;
> >> #endif
> >>
> >> // Part of ABI, do not change.
> >> -// https://github.com/llvm/llvm-project/blob/master/libcxx/include/atomic
> >> +// https://github.com/llvm/llvm-project/blob/main/libcxx/include/atomic
> >> typedef enum {
> >> __tsan_memory_order_relaxed,
> >> __tsan_memory_order_consume,
> >> diff --git a/libsanitizer/interception/interception_linux.cpp b/libsanitizer/interception/interception_linux.cpp
> >> index 6883608d44f..5111a87f0a6 100644
> >> --- a/libsanitizer/interception/interception_linux.cpp
> >> +++ b/libsanitizer/interception/interception_linux.cpp
> >> @@ -63,8 +63,8 @@ bool InterceptFunction(const char *name, uptr *ptr_to_real, uptr func,
> >> return addr && (func == wrapper);
> >> }
> >>
> >> -// Android and Solaris do not have dlvsym
> >> -#if !SANITIZER_ANDROID && !SANITIZER_SOLARIS
> >> +// dlvsym is a GNU extension supported by some other platforms.
> >> +#if SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD
> >> static void *GetFuncAddr(const char *name, const char *ver) {
> >> return dlvsym(RTLD_NEXT, name, ver);
> >> }
> >> @@ -75,7 +75,7 @@ bool InterceptFunction(const char *name, const char *ver, uptr *ptr_to_real,
> >> *ptr_to_real = (uptr)addr;
> >> return addr && (func == wrapper);
> >> }
> >> -#endif // !SANITIZER_ANDROID
> >> +#endif // SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD
> >>
> >> } // namespace __interception
> >>
> >> diff --git a/libsanitizer/interception/interception_linux.h b/libsanitizer/interception/interception_linux.h
> >> index 097375fd1c1..a08f8cb98c4 100644
> >> --- a/libsanitizer/interception/interception_linux.h
> >> +++ b/libsanitizer/interception/interception_linux.h
> >> @@ -35,8 +35,8 @@ bool InterceptFunction(const char *name, const char *ver, uptr *ptr_to_real,
> >> (::__interception::uptr) & (func), \
> >> (::__interception::uptr) & WRAP(func))
> >>
> >> -// Android and Solaris do not have dlvsym
> >> -#if !SANITIZER_ANDROID && !SANITIZER_SOLARIS
> >> +// dlvsym is a GNU extension supported by some other platforms.
> >> +#if SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD
> >> #define INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver) \
> >> ::__interception::InterceptFunction( \
> >> #func, symver, \
> >> @@ -46,7 +46,7 @@ bool InterceptFunction(const char *name, const char *ver, uptr *ptr_to_real,
> >> #else
> >> #define INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver) \
> >> INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func)
> >> -#endif // !SANITIZER_ANDROID && !SANITIZER_SOLARIS
> >> +#endif // SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD
> >>
> >> #endif // INTERCEPTION_LINUX_H
> >> #endif // SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD ||
> >> diff --git a/libsanitizer/interception/interception_win.cpp b/libsanitizer/interception/interception_win.cpp
> >> index 1a1c327e612..98bc756ae53 100644
> >> --- a/libsanitizer/interception/interception_win.cpp
> >> +++ b/libsanitizer/interception/interception_win.cpp
> >> @@ -136,7 +136,7 @@ namespace __interception {
> >> static const int kAddressLength = FIRST_32_SECOND_64(4, 8);
> >> static const int kJumpInstructionLength = 5;
> >> static const int kShortJumpInstructionLength = 2;
> >> -static const int kIndirectJumpInstructionLength = 6;
> >> +UNUSED static const int kIndirectJumpInstructionLength = 6;
> >> static const int kBranchLength =
> >> FIRST_32_SECOND_64(kJumpInstructionLength, kIndirectJumpInstructionLength);
> >> static const int kDirectBranchLength = kBranchLength + kAddressLength;
> >> @@ -165,7 +165,7 @@ static uptr GetMmapGranularity() {
> >> return si.dwAllocationGranularity;
> >> }
> >>
> >> -static uptr RoundUpTo(uptr size, uptr boundary) {
> >> +UNUSED static uptr RoundUpTo(uptr size, uptr boundary) {
> >> return (size + boundary - 1) & ~(boundary - 1);
> >> }
> >>
> >> @@ -309,7 +309,7 @@ struct TrampolineMemoryRegion {
> >> uptr max_size;
> >> };
> >>
> >> -static const uptr kTrampolineScanLimitRange = 1 << 31; // 2 gig
> >> +UNUSED static const uptr kTrampolineScanLimitRange = 1 << 31; // 2 gig
> >> static const int kMaxTrampolineRegion = 1024;
> >> static TrampolineMemoryRegion TrampolineRegions[kMaxTrampolineRegion];
> >>
> >> diff --git a/libsanitizer/lsan/lsan_allocator.cpp b/libsanitizer/lsan/lsan_allocator.cpp
> >> index d86c3921395..91e34ebb321 100644
> >> --- a/libsanitizer/lsan/lsan_allocator.cpp
> >> +++ b/libsanitizer/lsan/lsan_allocator.cpp
> >> @@ -123,14 +123,18 @@ void Deallocate(void *p) {
> >>
> >> void *Reallocate(const StackTrace &stack, void *p, uptr new_size,
> >> uptr alignment) {
> >> - RegisterDeallocation(p);
> >> if (new_size > max_malloc_size) {
> >> - allocator.Deallocate(GetAllocatorCache(), p);
> >> - return ReportAllocationSizeTooBig(new_size, stack);
> >> + ReportAllocationSizeTooBig(new_size, stack);
> >> + return nullptr;
> >> }
> >> - p = allocator.Reallocate(GetAllocatorCache(), p, new_size, alignment);
> >> - RegisterAllocation(stack, p, new_size);
> >> - return p;
> >> + RegisterDeallocation(p);
> >> + void *new_p =
> >> + allocator.Reallocate(GetAllocatorCache(), p, new_size, alignment);
> >> + if (new_p)
> >> + RegisterAllocation(stack, new_p, new_size);
> >> + else if (new_size != 0)
> >> + RegisterAllocation(stack, p, new_size);
> >> + return new_p;
> >> }
> >>
> >> void GetAllocatorCacheRange(uptr *begin, uptr *end) {
> >> @@ -309,6 +313,16 @@ IgnoreObjectResult IgnoreObjectLocked(const void *p) {
> >> return kIgnoreObjectInvalid;
> >> }
> >> }
> >> +
> >> +void GetAdditionalThreadContextPtrs(ThreadContextBase *tctx, void *ptrs) {
> >> + // This function can be used to treat memory reachable from `tctx` as live.
> >> + // This is useful for threads that have been created but not yet started.
> >> +
> >> + // This is currently a no-op because the LSan `pthread_create()` interceptor
> >> + // blocks until the child thread starts which keeps the thread's `arg` pointer
> >> + // live.
> >> +}
> >> +
> >> } // namespace __lsan
> >>
> >> using namespace __lsan;
> >> diff --git a/libsanitizer/lsan/lsan_allocator.h b/libsanitizer/lsan/lsan_allocator.h
> >> index 17e13cd014b..9d763789154 100644
> >> --- a/libsanitizer/lsan/lsan_allocator.h
> >> +++ b/libsanitizer/lsan/lsan_allocator.h
> >> @@ -50,7 +50,7 @@ struct ChunkMetadata {
> >> };
> >>
> >> #if defined(__mips64) || defined(__aarch64__) || defined(__i386__) || \
> >> - defined(__arm__)
> >> + defined(__arm__) || SANITIZER_RISCV64
> >> template <typename AddressSpaceViewTy>
> >> struct AP32 {
> >> static const uptr kSpaceBeg = 0;
> >> diff --git a/libsanitizer/lsan/lsan_common.cpp b/libsanitizer/lsan/lsan_common.cpp
> >> index 9e23aa9997a..74400d2e842 100644
> >> --- a/libsanitizer/lsan/lsan_common.cpp
> >> +++ b/libsanitizer/lsan/lsan_common.cpp
> >> @@ -65,8 +65,34 @@ void RegisterLsanFlags(FlagParser *parser, Flags *f) {
> >> if (flags()->log_threads) Report(__VA_ARGS__); \
> >> } while (0)
> >>
> >> -ALIGNED(64) static char suppression_placeholder[sizeof(SuppressionContext)];
> >> -static SuppressionContext *suppression_ctx = nullptr;
> >> +class LeakSuppressionContext {
> >> + bool parsed = false;
> >> + SuppressionContext context;
> >> + bool suppressed_stacks_sorted = true;
> >> + InternalMmapVector<u32> suppressed_stacks;
> >> +
> >> + Suppression *GetSuppressionForAddr(uptr addr);
> >> + void LazyInit();
> >> +
> >> + public:
> >> + LeakSuppressionContext(const char *supprression_types[],
> >> + int suppression_types_num)
> >> + : context(supprression_types, suppression_types_num) {}
> >> +
> >> + Suppression *GetSuppressionForStack(u32 stack_trace_id);
> >> +
> >> + const InternalMmapVector<u32> &GetSortedSuppressedStacks() {
> >> + if (!suppressed_stacks_sorted) {
> >> + suppressed_stacks_sorted = true;
> >> + SortAndDedup(suppressed_stacks);
> >> + }
> >> + return suppressed_stacks;
> >> + }
> >> + void PrintMatchedSuppressions();
> >> +};
> >> +
> >> +ALIGNED(64) static char suppression_placeholder[sizeof(LeakSuppressionContext)];
> >> +static LeakSuppressionContext *suppression_ctx = nullptr;
> >> static const char kSuppressionLeak[] = "leak";
> >> static const char *kSuppressionTypes[] = { kSuppressionLeak };
> >> static const char kStdSuppressions[] =
> >> @@ -86,14 +112,20 @@ static const char kStdSuppressions[] =
> >> void InitializeSuppressions() {
> >> CHECK_EQ(nullptr, suppression_ctx);
> >> suppression_ctx = new (suppression_placeholder)
> >> - SuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes));
> >> - suppression_ctx->ParseFromFile(flags()->suppressions);
> >> - if (&__lsan_default_suppressions)
> >> - suppression_ctx->Parse(__lsan_default_suppressions());
> >> - suppression_ctx->Parse(kStdSuppressions);
> >> + LeakSuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes));
> >> +}
> >> +
> >> +void LeakSuppressionContext::LazyInit() {
> >> + if (!parsed) {
> >> + parsed = true;
> >> + context.ParseFromFile(flags()->suppressions);
> >> + if (&__lsan_default_suppressions)
> >> + context.Parse(__lsan_default_suppressions());
> >> + context.Parse(kStdSuppressions);
> >> + }
> >> }
> >>
> >> -static SuppressionContext *GetSuppressionContext() {
> >> +static LeakSuppressionContext *GetSuppressionContext() {
> >> CHECK(suppression_ctx);
> >> return suppression_ctx;
> >> }
> >> @@ -221,6 +253,27 @@ extern "C" SANITIZER_WEAK_ATTRIBUTE void __libc_iterate_dynamic_tls(
> >> pid_t, void (*cb)(void *, void *, uptr, void *), void *);
> >> #endif
> >>
> >> +static void ProcessThreadRegistry(Frontier *frontier) {
> >> + InternalMmapVector<uptr> ptrs;
> >> + GetThreadRegistryLocked()->RunCallbackForEachThreadLocked(
> >> + GetAdditionalThreadContextPtrs, &ptrs);
> >> +
> >> + for (uptr i = 0; i < ptrs.size(); ++i) {
> >> + void *ptr = reinterpret_cast<void *>(ptrs[i]);
> >> + uptr chunk = PointsIntoChunk(ptr);
> >> + if (!chunk)
> >> + continue;
> >> + LsanMetadata m(chunk);
> >> + if (!m.allocated())
> >> + continue;
> >> +
> >> + // Mark as reachable and add to frontier.
> >> + LOG_POINTERS("Treating pointer %p from ThreadContext as reachable\n", ptr);
> >> + m.set_tag(kReachable);
> >> + frontier->push_back(chunk);
> >> + }
> >> +}
> >> +
> >> // Scans thread data (stacks and TLS) for heap pointers.
> >> static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
> >> Frontier *frontier) {
> >> @@ -315,15 +368,15 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
> >> __libc_iterate_dynamic_tls(os_id, cb, frontier);
> >> #else
> >> if (dtls && !DTLSInDestruction(dtls)) {
> >> - for (uptr j = 0; j < dtls->dtv_size; ++j) {
> >> - uptr dtls_beg = dtls->dtv[j].beg;
> >> - uptr dtls_end = dtls_beg + dtls->dtv[j].size;
> >> + ForEachDVT(dtls, [&](const DTLS::DTV &dtv, int id) {
> >> + uptr dtls_beg = dtv.beg;
> >> + uptr dtls_end = dtls_beg + dtv.size;
> >> if (dtls_beg < dtls_end) {
> >> - LOG_THREADS("DTLS %zu at %p-%p.\n", j, dtls_beg, dtls_end);
> >> + LOG_THREADS("DTLS %zu at %p-%p.\n", id, dtls_beg, dtls_end);
> >> ScanRangeForPointers(dtls_beg, dtls_end, frontier, "DTLS",
> >> kReachable);
> >> }
> >> - }
> >> + });
> >> } else {
> >> // We are handling a thread with DTLS under destruction. Log about
> >> // this and continue.
> >> @@ -332,6 +385,9 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
> >> #endif
> >> }
> >> }
> >> +
> >> + // Add pointers reachable from ThreadContexts
> >> + ProcessThreadRegistry(frontier);
> >> }
> >>
> >> #endif // SANITIZER_FUCHSIA
> >> @@ -390,6 +446,24 @@ static void MarkIndirectlyLeakedCb(uptr chunk, void *arg) {
> >> }
> >> }
> >>
> >> +static void IgnoredSuppressedCb(uptr chunk, void *arg) {
> >> + CHECK(arg);
> >> + chunk = GetUserBegin(chunk);
> >> + LsanMetadata m(chunk);
> >> + if (!m.allocated() || m.tag() == kIgnored)
> >> + return;
> >> +
> >> + const InternalMmapVector<u32> &suppressed =
> >> + *static_cast<const InternalMmapVector<u32> *>(arg);
> >> + uptr idx = InternalLowerBound(suppressed, m.stack_trace_id());
> >> + if (idx >= suppressed.size() || m.stack_trace_id() != suppressed[idx])
> >> + return;
> >> +
> >> + LOG_POINTERS("Suppressed: chunk %p-%p of size %zu.\n", chunk,
> >> + chunk + m.requested_size(), m.requested_size());
> >> + m.set_tag(kIgnored);
> >> +}
> >> +
> >> // ForEachChunk callback. If chunk is marked as ignored, adds its address to
> >> // frontier.
> >> static void CollectIgnoredCb(uptr chunk, void *arg) {
> >> @@ -473,6 +547,12 @@ void ProcessPC(Frontier *frontier) {
> >> // Sets the appropriate tag on each chunk.
> >> static void ClassifyAllChunks(SuspendedThreadsList const &suspended_threads,
> >> Frontier *frontier) {
> >> + const InternalMmapVector<u32> &suppressed_stacks =
> >> + GetSuppressionContext()->GetSortedSuppressedStacks();
> >> + if (!suppressed_stacks.empty()) {
> >> + ForEachChunk(IgnoredSuppressedCb,
> >> + const_cast<InternalMmapVector<u32> *>(&suppressed_stacks));
> >> + }
> >> ForEachChunk(CollectIgnoredCb, frontier);
> >> ProcessGlobalRegions(frontier);
> >> ProcessThreads(suspended_threads, frontier);
> >> @@ -532,18 +612,20 @@ static void CollectLeaksCb(uptr chunk, void *arg) {
> >> }
> >> }
> >>
> >> -static void PrintMatchedSuppressions() {
> >> +void LeakSuppressionContext::PrintMatchedSuppressions() {
> >> InternalMmapVector<Suppression *> matched;
> >> - GetSuppressionContext()->GetMatched(&matched);
> >> + context.GetMatched(&matched);
> >> if (!matched.size())
> >> return;
> >> const char *line = "-----------------------------------------------------";
> >> Printf("%s\n", line);
> >> Printf("Suppressions used:\n");
> >> Printf(" count bytes template\n");
> >> - for (uptr i = 0; i < matched.size(); i++)
> >> - Printf("%7zu %10zu %s\n", static_cast<uptr>(atomic_load_relaxed(
> >> - &matched[i]->hit_count)), matched[i]->weight, matched[i]->templ);
> >> + for (uptr i = 0; i < matched.size(); i++) {
> >> + Printf("%7zu %10zu %s\n",
> >> + static_cast<uptr>(atomic_load_relaxed(&matched[i]->hit_count)),
> >> + matched[i]->weight, matched[i]->templ);
> >> + }
> >> Printf("%s\n\n", line);
> >> }
> >>
> >> @@ -551,8 +633,7 @@ static void ReportIfNotSuspended(ThreadContextBase *tctx, void *arg) {
> >> const InternalMmapVector<tid_t> &suspended_threads =
> >> *(const InternalMmapVector<tid_t> *)arg;
> >> if (tctx->status == ThreadStatusRunning) {
> >> - uptr i = InternalLowerBound(suspended_threads, 0, suspended_threads.size(),
> >> - tctx->os_id, CompareLess<int>());
> >> + uptr i = InternalLowerBound(suspended_threads, tctx->os_id);
> >> if (i >= suspended_threads.size() || suspended_threads[i] != tctx->os_id)
> >> Report("Running thread %d was not suspended. False leaks are possible.\n",
> >> tctx->os_id);
> >> @@ -595,43 +676,68 @@ static void CheckForLeaksCallback(const SuspendedThreadsList &suspended_threads,
> >> param->success = true;
> >> }
> >>
> >> -static bool CheckForLeaks() {
> >> - if (&__lsan_is_turned_off && __lsan_is_turned_off())
> >> - return false;
> >> - EnsureMainThreadIDIsCorrect();
> >> - CheckForLeaksParam param;
> >> - LockStuffAndStopTheWorld(CheckForLeaksCallback, ¶m);
> >> -
> >> - if (!param.success) {
> >> - Report("LeakSanitizer has encountered a fatal error.\n");
> >> - Report(
> >> - "HINT: For debugging, try setting environment variable "
> >> - "LSAN_OPTIONS=verbosity=1:log_threads=1\n");
> >> - Report(
> >> - "HINT: LeakSanitizer does not work under ptrace (strace, gdb, etc)\n");
> >> - Die();
> >> - }
> >> - param.leak_report.ApplySuppressions();
> >> - uptr unsuppressed_count = param.leak_report.UnsuppressedLeakCount();
> >> - if (unsuppressed_count > 0) {
> >> +static bool PrintResults(LeakReport &report) {
> >> + uptr unsuppressed_count = report.UnsuppressedLeakCount();
> >> + if (unsuppressed_count) {
> >> Decorator d;
> >> - Printf("\n"
> >> - "================================================================="
> >> - "\n");
> >> + Printf(
> >> + "\n"
> >> + "================================================================="
> >> + "\n");
> >> Printf("%s", d.Error());
> >> Report("ERROR: LeakSanitizer: detected memory leaks\n");
> >> Printf("%s", d.Default());
> >> - param.leak_report.ReportTopLeaks(flags()->max_leaks);
> >> + report.ReportTopLeaks(flags()->max_leaks);
> >> }
> >> if (common_flags()->print_suppressions)
> >> - PrintMatchedSuppressions();
> >> + GetSuppressionContext()->PrintMatchedSuppressions();
> >> if (unsuppressed_count > 0) {
> >> - param.leak_report.PrintSummary();
> >> + report.PrintSummary();
> >> return true;
> >> }
> >> return false;
> >> }
> >>
> >> +static bool CheckForLeaks() {
> >> + if (&__lsan_is_turned_off && __lsan_is_turned_off())
> >> + return false;
> >> + // Inside LockStuffAndStopTheWorld we can't run symbolizer, so we can't match
> >> + // suppressions. However if a stack id was previously suppressed, it should be
> >> + // suppressed in future checks as well.
> >> + for (int i = 0;; ++i) {
> >> + EnsureMainThreadIDIsCorrect();
> >> + CheckForLeaksParam param;
> >> + LockStuffAndStopTheWorld(CheckForLeaksCallback, ¶m);
> >> + if (!param.success) {
> >> + Report("LeakSanitizer has encountered a fatal error.\n");
> >> + Report(
> >> + "HINT: For debugging, try setting environment variable "
> >> + "LSAN_OPTIONS=verbosity=1:log_threads=1\n");
> >> + Report(
> >> + "HINT: LeakSanitizer does not work under ptrace (strace, gdb, "
> >> + "etc)\n");
> >> + Die();
> >> + }
> >> + // No new suppressions stacks, so rerun will not help and we can report.
> >> + if (!param.leak_report.ApplySuppressions())
> >> + return PrintResults(param.leak_report);
> >> +
> >> + // No indirect leaks to report, so we are done here.
> >> + if (!param.leak_report.IndirectUnsuppressedLeakCount())
> >> + return PrintResults(param.leak_report);
> >> +
> >> + if (i >= 8) {
> >> + Report("WARNING: LeakSanitizer gave up on indirect leaks suppression.\n");
> >> + return PrintResults(param.leak_report);
> >> + }
> >> +
> >> + // We found a new previously unseen suppressed call stack. Rerun to make
> >> + // sure it does not hold indirect leaks.
> >> + VReport(1, "Rerun with %zu suppressed stacks.",
> >> + GetSuppressionContext()->GetSortedSuppressedStacks().size());
> >> + }
> >> +}
> >> +
> >> static bool has_reported_leaks = false;
> >> bool HasReportedLeaks() { return has_reported_leaks; }
> >>
> >> @@ -652,21 +758,20 @@ static int DoRecoverableLeakCheck() {
> >>
> >> void DoRecoverableLeakCheckVoid() { DoRecoverableLeakCheck(); }
> >>
> >> -static Suppression *GetSuppressionForAddr(uptr addr) {
> >> +Suppression *LeakSuppressionContext::GetSuppressionForAddr(uptr addr) {
> >> Suppression *s = nullptr;
> >>
> >> // Suppress by module name.
> >> - SuppressionContext *suppressions = GetSuppressionContext();
> >> if (const char *module_name =
> >> Symbolizer::GetOrInit()->GetModuleNameForPc(addr))
> >> - if (suppressions->Match(module_name, kSuppressionLeak, &s))
> >> + if (context.Match(module_name, kSuppressionLeak, &s))
> >> return s;
> >>
> >> // Suppress by file or function name.
> >> SymbolizedStack *frames = Symbolizer::GetOrInit()->SymbolizePC(addr);
> >> for (SymbolizedStack *cur = frames; cur; cur = cur->next) {
> >> - if (suppressions->Match(cur->info.function, kSuppressionLeak, &s) ||
> >> - suppressions->Match(cur->info.file, kSuppressionLeak, &s)) {
> >> + if (context.Match(cur->info.function, kSuppressionLeak, &s) ||
> >> + context.Match(cur->info.file, kSuppressionLeak, &s)) {
> >> break;
> >> }
> >> }
> >> @@ -674,12 +779,18 @@ static Suppression *GetSuppressionForAddr(uptr addr) {
> >> return s;
> >> }
> >>
> >> -static Suppression *GetSuppressionForStack(u32 stack_trace_id) {
> >> +Suppression *LeakSuppressionContext::GetSuppressionForStack(
> >> + u32 stack_trace_id) {
> >> + LazyInit();
> >> StackTrace stack = StackDepotGet(stack_trace_id);
> >> for (uptr i = 0; i < stack.size; i++) {
> >> Suppression *s = GetSuppressionForAddr(
> >> StackTrace::GetPreviousInstructionPc(stack.trace[i]));
> >> - if (s) return s;
> >> + if (s) {
> >> + suppressed_stacks_sorted = false;
> >> + suppressed_stacks.push_back(stack_trace_id);
> >> + return s;
> >> + }
> >> }
> >> return nullptr;
> >> }
> >> @@ -784,22 +895,27 @@ void LeakReport::PrintSummary() {
> >> bytes += leaks_[i].total_size;
> >> allocations += leaks_[i].hit_count;
> >> }
> >> - InternalScopedString summary(kMaxSummaryLength);
> >> + InternalScopedString summary;
> >> summary.append("%zu byte(s) leaked in %zu allocation(s).", bytes,
> >> allocations);
> >> ReportErrorSummary(summary.data());
> >> }
> >>
> >> -void LeakReport::ApplySuppressions() {
> >> +uptr LeakReport::ApplySuppressions() {
> >> + LeakSuppressionContext *suppressions = GetSuppressionContext();
> >> + uptr new_suppressions = false;
> >> for (uptr i = 0; i < leaks_.size(); i++) {
> >> - Suppression *s = GetSuppressionForStack(leaks_[i].stack_trace_id);
> >> + Suppression *s =
> >> + suppressions->GetSuppressionForStack(leaks_[i].stack_trace_id);
> >> if (s) {
> >> s->weight += leaks_[i].total_size;
> >> atomic_store_relaxed(&s->hit_count, atomic_load_relaxed(&s->hit_count) +
> >> leaks_[i].hit_count);
> >> leaks_[i].is_suppressed = true;
> >> + ++new_suppressions;
> >> }
> >> }
> >> + return new_suppressions;
> >> }
> >>
> >> uptr LeakReport::UnsuppressedLeakCount() {
> >> @@ -809,6 +925,14 @@ uptr LeakReport::UnsuppressedLeakCount() {
> >> return result;
> >> }
> >>
> >> +uptr LeakReport::IndirectUnsuppressedLeakCount() {
> >> + uptr result = 0;
> >> + for (uptr i = 0; i < leaks_.size(); i++)
> >> + if (!leaks_[i].is_suppressed && !leaks_[i].is_directly_leaked)
> >> + result++;
> >> + return result;
> >> +}
> >> +
> >> } // namespace __lsan
> >> #else // CAN_SANITIZE_LEAKS
> >> namespace __lsan {
> >> diff --git a/libsanitizer/lsan/lsan_common.h b/libsanitizer/lsan/lsan_common.h
> >> index 1fdce087b3a..fe855cf3754 100644
> >> --- a/libsanitizer/lsan/lsan_common.h
> >> +++ b/libsanitizer/lsan/lsan_common.h
> >> @@ -41,6 +41,8 @@
> >> #define CAN_SANITIZE_LEAKS 1
> >> #elif defined(__arm__) && SANITIZER_LINUX
> >> #define CAN_SANITIZE_LEAKS 1
> >> +#elif SANITIZER_RISCV64 && SANITIZER_LINUX
> >> +#define CAN_SANITIZE_LEAKS 1
> >> #elif SANITIZER_NETBSD || SANITIZER_FUCHSIA
> >> #define CAN_SANITIZE_LEAKS 1
> >> #else
> >> @@ -50,6 +52,7 @@
> >> namespace __sanitizer {
> >> class FlagParser;
> >> class ThreadRegistry;
> >> +class ThreadContextBase;
> >> struct DTLS;
> >> }
> >>
> >> @@ -63,8 +66,6 @@ enum ChunkTag {
> >> kIgnored = 3
> >> };
> >>
> >> -const u32 kInvalidTid = (u32) -1;
> >> -
> >> struct Flags {
> >> #define LSAN_FLAG(Type, Name, DefaultValue, Description) Type Name;
> >> #include "lsan_flags.inc"
> >> @@ -103,8 +104,9 @@ class LeakReport {
> >> ChunkTag tag);
> >> void ReportTopLeaks(uptr max_leaks);
> >> void PrintSummary();
> >> - void ApplySuppressions();
> >> + uptr ApplySuppressions();
> >> uptr UnsuppressedLeakCount();
> >> + uptr IndirectUnsuppressedLeakCount();
> >>
> >> private:
> >> void PrintReportForLeak(uptr index);
> >> @@ -141,6 +143,7 @@ InternalMmapVector<RootRegion> const *GetRootRegions();
> >> void ScanRootRegion(Frontier *frontier, RootRegion const ®ion,
> >> uptr region_begin, uptr region_end, bool is_readable);
> >> void ForEachExtraStackRangeCb(uptr begin, uptr end, void* arg);
> >> +void GetAdditionalThreadContextPtrs(ThreadContextBase *tctx, void *ptrs);
> >> // Run stoptheworld while holding any platform-specific locks, as well as the
> >> // allocator and thread registry locks.
> >> void LockStuffAndStopTheWorld(StopTheWorldCallback callback,
> >> diff --git a/libsanitizer/lsan/lsan_common_fuchsia.cpp b/libsanitizer/lsan/lsan_common_fuchsia.cpp
> >> index 3c62c9433d3..2d35fa5b1cf 100644
> >> --- a/libsanitizer/lsan/lsan_common_fuchsia.cpp
> >> +++ b/libsanitizer/lsan/lsan_common_fuchsia.cpp
> >> @@ -107,9 +107,7 @@ void LockStuffAndStopTheWorld(StopTheWorldCallback callback,
> >> auto params = static_cast<const Params *>(data);
> >> uptr begin = reinterpret_cast<uptr>(chunk);
> >> uptr end = begin + size;
> >> - auto i = __sanitizer::InternalLowerBound(params->allocator_caches, 0,
> >> - params->allocator_caches.size(),
> >> - begin, CompareLess<uptr>());
> >> + auto i = __sanitizer::InternalLowerBound(params->allocator_caches, begin);
> >> if (i < params->allocator_caches.size() &&
> >> params->allocator_caches[i] >= begin &&
> >> end - params->allocator_caches[i] <= sizeof(AllocatorCache)) {
> >> diff --git a/libsanitizer/lsan/lsan_fuchsia.h b/libsanitizer/lsan/lsan_fuchsia.h
> >> index 65d20ea2114..e730d8f25f2 100644
> >> --- a/libsanitizer/lsan/lsan_fuchsia.h
> >> +++ b/libsanitizer/lsan/lsan_fuchsia.h
> >> @@ -23,7 +23,7 @@
> >>
> >> namespace __lsan {
> >>
> >> -class ThreadContext : public ThreadContextLsanBase {
> >> +class ThreadContext final : public ThreadContextLsanBase {
> >> public:
> >> explicit ThreadContext(int tid);
> >> void OnCreated(void *arg) override;
> >> diff --git a/libsanitizer/lsan/lsan_interceptors.cpp b/libsanitizer/lsan/lsan_interceptors.cpp
> >> index bf8d316770e..90a90a56c54 100644
> >> --- a/libsanitizer/lsan/lsan_interceptors.cpp
> >> +++ b/libsanitizer/lsan/lsan_interceptors.cpp
> >> @@ -460,7 +460,7 @@ INTERCEPTOR(int, pthread_create, void *th, void *attr,
> >> if (res == 0) {
> >> int tid = ThreadCreate(GetCurrentThread(), *(uptr *)th,
> >> IsStateDetached(detached));
> >> - CHECK_NE(tid, 0);
> >> + CHECK_NE(tid, kMainTid);
> >> atomic_store(&p.tid, tid, memory_order_release);
> >> while (atomic_load(&p.tid, memory_order_acquire) != 0)
> >> internal_sched_yield();
> >> diff --git a/libsanitizer/lsan/lsan_posix.cpp b/libsanitizer/lsan/lsan_posix.cpp
> >> index 8e05915dd1b..5d1c3f6260d 100644
> >> --- a/libsanitizer/lsan/lsan_posix.cpp
> >> +++ b/libsanitizer/lsan/lsan_posix.cpp
> >> @@ -48,7 +48,7 @@ void ThreadStart(u32 tid, tid_t os_id, ThreadType thread_type) {
> >> OnStartedArgs args;
> >> uptr stack_size = 0;
> >> uptr tls_size = 0;
> >> - GetThreadStackAndTls(tid == 0, &args.stack_begin, &stack_size,
> >> + GetThreadStackAndTls(tid == kMainTid, &args.stack_begin, &stack_size,
> >> &args.tls_begin, &tls_size);
> >> args.stack_end = args.stack_begin + stack_size;
> >> args.tls_end = args.tls_begin + tls_size;
> >> @@ -75,8 +75,8 @@ bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end,
> >> }
> >>
> >> void InitializeMainThread() {
> >> - u32 tid = ThreadCreate(0, 0, true);
> >> - CHECK_EQ(tid, 0);
> >> + u32 tid = ThreadCreate(kMainTid, 0, true);
> >> + CHECK_EQ(tid, kMainTid);
> >> ThreadStart(tid, GetTid());
> >> }
> >>
> >> diff --git a/libsanitizer/lsan/lsan_thread.cpp b/libsanitizer/lsan/lsan_thread.cpp
> >> index 371a1f29dfe..8efb54a6fb7 100644
> >> --- a/libsanitizer/lsan/lsan_thread.cpp
> >> +++ b/libsanitizer/lsan/lsan_thread.cpp
> >> @@ -94,7 +94,7 @@ void ThreadJoin(u32 tid) {
> >> }
> >>
> >> void EnsureMainThreadIDIsCorrect() {
> >> - if (GetCurrentThread() == 0)
> >> + if (GetCurrentThread() == kMainTid)
> >> CurrentThreadContext()->os_id = GetTid();
> >> }
> >>
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_combined.h b/libsanitizer/sanitizer_common/sanitizer_allocator_combined.h
> >> index 33f89d6d499..eb836bc4787 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_allocator_combined.h
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_allocator_combined.h
> >> @@ -35,9 +35,9 @@ class CombinedAllocator {
> >> secondary_.InitLinkerInitialized();
> >> }
> >>
> >> - void Init(s32 release_to_os_interval_ms) {
> >> + void Init(s32 release_to_os_interval_ms, uptr heap_start = 0) {
> >> stats_.Init();
> >> - primary_.Init(release_to_os_interval_ms);
> >> + primary_.Init(release_to_os_interval_ms, heap_start);
> >> secondary_.Init();
> >> }
> >>
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_primary32.h b/libsanitizer/sanitizer_common/sanitizer_allocator_primary32.h
> >> index b90dabbf776..fb5394cd39c 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_allocator_primary32.h
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_allocator_primary32.h
> >> @@ -119,7 +119,8 @@ class SizeClassAllocator32 {
> >> typedef SizeClassAllocator32<Params> ThisT;
> >> typedef SizeClassAllocator32LocalCache<ThisT> AllocatorCache;
> >>
> >> - void Init(s32 release_to_os_interval_ms) {
> >> + void Init(s32 release_to_os_interval_ms, uptr heap_start = 0) {
> >> + CHECK(!heap_start);
> >> possible_regions.Init();
> >> internal_memset(size_class_info_array, 0, sizeof(size_class_info_array));
> >> }
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_primary64.h b/libsanitizer/sanitizer_common/sanitizer_allocator_primary64.h
> >> index 0a18b0c58ef..db30e138154 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_allocator_primary64.h
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_allocator_primary64.h
> >> @@ -19,7 +19,7 @@ template<class SizeClassAllocator> struct SizeClassAllocator64LocalCache;
> >> // The template parameter Params is a class containing the actual parameters.
> >> //
> >> // Space: a portion of address space of kSpaceSize bytes starting at SpaceBeg.
> >> -// If kSpaceBeg is ~0 then SpaceBeg is chosen dynamically my mmap.
> >> +// If kSpaceBeg is ~0 then SpaceBeg is chosen dynamically by mmap.
> >> // Otherwise SpaceBeg=kSpaceBeg (fixed address).
> >> // kSpaceSize is a power of two.
> >> // At the beginning the entire space is mprotect-ed, then small parts of it
> >> @@ -69,25 +69,45 @@ class SizeClassAllocator64 {
> >> return base + (static_cast<uptr>(ptr32) << kCompactPtrScale);
> >> }
> >>
> >> - void Init(s32 release_to_os_interval_ms) {
> >> + // If heap_start is nonzero, assumes kSpaceSize bytes are already mapped R/W
> >> + // at heap_start and places the heap there. This mode requires kSpaceBeg ==
> >> + // ~(uptr)0.
> >> + void Init(s32 release_to_os_interval_ms, uptr heap_start = 0) {
> >> uptr TotalSpaceSize = kSpaceSize + AdditionalSize();
> >> - if (kUsingConstantSpaceBeg) {
> >> - CHECK(IsAligned(kSpaceBeg, SizeClassMap::kMaxSize));
> >> - CHECK_EQ(kSpaceBeg, address_range.Init(TotalSpaceSize,
> >> - PrimaryAllocatorName, kSpaceBeg));
> >> + PremappedHeap = heap_start != 0;
> >> + if (PremappedHeap) {
> >> + CHECK(!kUsingConstantSpaceBeg);
> >> + NonConstSpaceBeg = heap_start;
> >> + uptr RegionInfoSize = AdditionalSize();
> >> + RegionInfoSpace =
> >> + address_range.Init(RegionInfoSize, PrimaryAllocatorName);
> >> + CHECK_NE(RegionInfoSpace, ~(uptr)0);
> >> + CHECK_EQ(RegionInfoSpace,
> >> + address_range.MapOrDie(RegionInfoSpace, RegionInfoSize,
> >> + "SizeClassAllocator: region info"));
> >> + MapUnmapCallback().OnMap(RegionInfoSpace, RegionInfoSize);
> >> } else {
> >> - // Combined allocator expects that an 2^N allocation is always aligned to
> >> - // 2^N. For this to work, the start of the space needs to be aligned as
> >> - // high as the largest size class (which also needs to be a power of 2).
> >> - NonConstSpaceBeg = address_range.InitAligned(
> >> - TotalSpaceSize, SizeClassMap::kMaxSize, PrimaryAllocatorName);
> >> - CHECK_NE(NonConstSpaceBeg, ~(uptr)0);
> >> + if (kUsingConstantSpaceBeg) {
> >> + CHECK(IsAligned(kSpaceBeg, SizeClassMap::kMaxSize));
> >> + CHECK_EQ(kSpaceBeg,
> >> + address_range.Init(TotalSpaceSize, PrimaryAllocatorName,
> >> + kSpaceBeg));
> >> + } else {
> >> + // Combined allocator expects that an 2^N allocation is always aligned
> >> + // to 2^N. For this to work, the start of the space needs to be aligned
> >> + // as high as the largest size class (which also needs to be a power of
> >> + // 2).
> >> + NonConstSpaceBeg = address_range.InitAligned(
> >> + TotalSpaceSize, SizeClassMap::kMaxSize, PrimaryAllocatorName);
> >> + CHECK_NE(NonConstSpaceBeg, ~(uptr)0);
> >> + }
> >> + RegionInfoSpace = SpaceEnd();
> >> + MapWithCallbackOrDie(RegionInfoSpace, AdditionalSize(),
> >> + "SizeClassAllocator: region info");
> >> }
> >> SetReleaseToOSIntervalMs(release_to_os_interval_ms);
> >> - MapWithCallbackOrDie(SpaceEnd(), AdditionalSize(),
> >> - "SizeClassAllocator: region info");
> >> // Check that the RegionInfo array is aligned on the CacheLine size.
> >> - DCHECK_EQ(SpaceEnd() % kCacheLineSize, 0);
> >> + DCHECK_EQ(RegionInfoSpace % kCacheLineSize, 0);
> >> }
> >>
> >> s32 ReleaseToOSIntervalMs() const {
> >> @@ -144,6 +164,17 @@ class SizeClassAllocator64 {
> >> CompactPtrT *free_array = GetFreeArray(region_beg);
> >>
> >> BlockingMutexLock l(®ion->mutex);
> >> +#if SANITIZER_WINDOWS
> >> + /* On Windows unmapping of memory during __sanitizer_purge_allocator is
> >> + explicit and immediate, so unmapped regions must be explicitly mapped back
> >> + in when they are accessed again. */
> >> + if (region->rtoi.last_released_bytes > 0) {
> >> + MmapFixedOrDie(region_beg, region->mapped_user,
> >> + "SizeClassAllocator: region data");
> >> + region->rtoi.n_freed_at_last_release = 0;
> >> + region->rtoi.last_released_bytes = 0;
> >> + }
> >> +#endif
> >> if (UNLIKELY(region->num_freed_chunks < n_chunks)) {
> >> if (UNLIKELY(!PopulateFreeArray(stat, class_id, region,
> >> n_chunks - region->num_freed_chunks)))
> >> @@ -360,8 +391,7 @@ class SizeClassAllocator64 {
> >> }
> >> ~PackedCounterArray() {
> >> if (buffer) {
> >> - memory_mapper->UnmapPackedCounterArrayBuffer(
> >> - reinterpret_cast<uptr>(buffer), buffer_size);
> >> + memory_mapper->UnmapPackedCounterArrayBuffer(buffer, buffer_size);
> >> }
> >> }
> >>
> >> @@ -586,6 +616,11 @@ class SizeClassAllocator64 {
> >>
> >> atomic_sint32_t release_to_os_interval_ms_;
> >>
> >> + uptr RegionInfoSpace;
> >> +
> >> + // True if the user has already mapped the entire heap R/W.
> >> + bool PremappedHeap;
> >> +
> >> struct Stats {
> >> uptr n_allocated;
> >> uptr n_freed;
> >> @@ -615,7 +650,7 @@ class SizeClassAllocator64 {
> >>
> >> RegionInfo *GetRegionInfo(uptr class_id) const {
> >> DCHECK_LT(class_id, kNumClasses);
> >> - RegionInfo *regions = reinterpret_cast<RegionInfo *>(SpaceEnd());
> >> + RegionInfo *regions = reinterpret_cast<RegionInfo *>(RegionInfoSpace);
> >> return ®ions[class_id];
> >> }
> >>
> >> @@ -640,6 +675,9 @@ class SizeClassAllocator64 {
> >> }
> >>
> >> bool MapWithCallback(uptr beg, uptr size, const char *name) {
> >> + if (PremappedHeap)
> >> + return beg >= NonConstSpaceBeg &&
> >> + beg + size <= NonConstSpaceBeg + kSpaceSize;
> >> uptr mapped = address_range.Map(beg, size, name);
> >> if (UNLIKELY(!mapped))
> >> return false;
> >> @@ -649,11 +687,18 @@ class SizeClassAllocator64 {
> >> }
> >>
> >> void MapWithCallbackOrDie(uptr beg, uptr size, const char *name) {
> >> + if (PremappedHeap) {
> >> + CHECK_GE(beg, NonConstSpaceBeg);
> >> + CHECK_LE(beg + size, NonConstSpaceBeg + kSpaceSize);
> >> + return;
> >> + }
> >> CHECK_EQ(beg, address_range.MapOrDie(beg, size, name));
> >> MapUnmapCallback().OnMap(beg, size);
> >> }
> >>
> >> void UnmapWithCallbackOrDie(uptr beg, uptr size) {
> >> + if (PremappedHeap)
> >> + return;
> >> MapUnmapCallback().OnUnmap(beg, size);
> >> address_range.Unmap(beg, size);
> >> }
> >> @@ -792,17 +837,16 @@ class SizeClassAllocator64 {
> >> return released_bytes;
> >> }
> >>
> >> - uptr MapPackedCounterArrayBuffer(uptr buffer_size) {
> >> + void *MapPackedCounterArrayBuffer(uptr buffer_size) {
> >> // TODO(alekseyshl): The idea to explore is to check if we have enough
> >> // space between num_freed_chunks*sizeof(CompactPtrT) and
> >> // mapped_free_array to fit buffer_size bytes and use that space instead
> >> // of mapping a temporary one.
> >> - return reinterpret_cast<uptr>(
> >> - MmapOrDieOnFatalError(buffer_size, "ReleaseToOSPageCounters"));
> >> + return MmapOrDieOnFatalError(buffer_size, "ReleaseToOSPageCounters");
> >> }
> >>
> >> - void UnmapPackedCounterArrayBuffer(uptr buffer, uptr buffer_size) {
> >> - UnmapOrDie(reinterpret_cast<void *>(buffer), buffer_size);
> >> + void UnmapPackedCounterArrayBuffer(void *buffer, uptr buffer_size) {
> >> + UnmapOrDie(buffer, buffer_size);
> >> }
> >>
> >> // Releases [from, to) range of pages back to OS.
> >> @@ -823,6 +867,9 @@ class SizeClassAllocator64 {
> >>
> >> // Attempts to release RAM occupied by freed chunks back to OS. The region is
> >> // expected to be locked.
> >> + //
> >> + // TODO(morehouse): Support a callback on memory release so HWASan can release
> >> + // aliases as well.
> >> void MaybeReleaseToOS(uptr class_id, bool force) {
> >> RegionInfo *region = GetRegionInfo(class_id);
> >> const uptr chunk_size = ClassIdToSize(class_id);
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_size_class_map.h b/libsanitizer/sanitizer_common/sanitizer_allocator_size_class_map.h
> >> index 12d8c892307..c50d13303ed 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_allocator_size_class_map.h
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_allocator_size_class_map.h
> >> @@ -24,7 +24,7 @@
> >> // E.g. with kNumBits==3 all size classes after 2^kMidSizeLog
> >> // look like 0b1xx0..0, where x is either 0 or 1.
> >> //
> >> -// Example: kNumBits=3, kMidSizeLog=4, kMidSizeLog=8, kMaxSizeLog=17:
> >> +// Example: kNumBits=3, kMinSizeLog=4, kMidSizeLog=8, kMaxSizeLog=17:
> >> //
> >> // Classes 1 - 16 correspond to sizes 16 to 256 (size = class_id * 16).
> >> // Next 4 classes: 256 + i * 64 (i = 1 to 4).
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_atomic_clang_mips.h b/libsanitizer/sanitizer_common/sanitizer_atomic_clang_mips.h
> >> index 59155e9883e..2b39097112d 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_atomic_clang_mips.h
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_atomic_clang_mips.h
> >> @@ -41,7 +41,7 @@ inline atomic_uint64_t::Type atomic_fetch_add(volatile atomic_uint64_t *ptr,
> >> atomic_uint64_t::Type val,
> >> memory_order mo) {
> >> DCHECK(mo &
> >> - (memory_order_relaxed | memory_order_releasae | memory_order_seq_cst));
> >> + (memory_order_relaxed | memory_order_release | memory_order_seq_cst));
> >> DCHECK(!((uptr)ptr % sizeof(*ptr)));
> >>
> >> atomic_uint64_t::Type ret;
> >> @@ -67,7 +67,7 @@ inline bool atomic_compare_exchange_strong(volatile atomic_uint64_t *ptr,
> >> atomic_uint64_t::Type xchg,
> >> memory_order mo) {
> >> DCHECK(mo &
> >> - (memory_order_relaxed | memory_order_releasae | memory_order_seq_cst));
> >> + (memory_order_relaxed | memory_order_release | memory_order_seq_cst));
> >> DCHECK(!((uptr)ptr % sizeof(*ptr)));
> >>
> >> typedef atomic_uint64_t::Type Type;
> >> @@ -90,7 +90,7 @@ template <>
> >> inline atomic_uint64_t::Type atomic_load(const volatile atomic_uint64_t *ptr,
> >> memory_order mo) {
> >> DCHECK(mo &
> >> - (memory_order_relaxed | memory_order_releasae | memory_order_seq_cst));
> >> + (memory_order_relaxed | memory_order_release | memory_order_seq_cst));
> >> DCHECK(!((uptr)ptr % sizeof(*ptr)));
> >>
> >> atomic_uint64_t::Type zero = 0;
> >> @@ -103,7 +103,7 @@ template <>
> >> inline void atomic_store(volatile atomic_uint64_t *ptr, atomic_uint64_t::Type v,
> >> memory_order mo) {
> >> DCHECK(mo &
> >> - (memory_order_relaxed | memory_order_releasae | memory_order_seq_cst));
> >> + (memory_order_relaxed | memory_order_release | memory_order_seq_cst));
> >> DCHECK(!((uptr)ptr % sizeof(*ptr)));
> >>
> >> __spin_lock(&lock.lock);
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_chained_origin_depot.cpp b/libsanitizer/sanitizer_common/sanitizer_chained_origin_depot.cpp
> >> new file mode 100644
> >> index 00000000000..250ac39e130
> >> --- /dev/null
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_chained_origin_depot.cpp
> >> @@ -0,0 +1,108 @@
> >> +//===-- sanitizer_chained_origin_depot.cpp --------------------------------===//
> >> +//
> >> +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
> >> +// See https://llvm.org/LICENSE.txt for license information.
> >> +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
> >> +//
> >> +//===----------------------------------------------------------------------===//
> >> +//
> >> +// A storage for chained origins.
> >> +//===----------------------------------------------------------------------===//
> >> +
> >> +#include "sanitizer_chained_origin_depot.h"
> >> +
> >> +namespace __sanitizer {
> >> +
> >> +bool ChainedOriginDepot::ChainedOriginDepotNode::eq(
> >> + u32 hash, const args_type &args) const {
> >> + return here_id == args.here_id && prev_id == args.prev_id;
> >> +}
> >> +
> >> +uptr ChainedOriginDepot::ChainedOriginDepotNode::storage_size(
> >> + const args_type &args) {
> >> + return sizeof(ChainedOriginDepotNode);
> >> +}
> >> +
> >> +/* This is murmur2 hash for the 64->32 bit case.
> >> + It does not behave all that well because the keys have a very biased
> >> + distribution (I've seen 7-element buckets with the table only 14% full).
> >> +
> >> + here_id is built of
> >> + * (1 bits) Reserved, zero.
> >> + * (8 bits) Part id = bits 13..20 of the hash value of here_id's key.
> >> + * (23 bits) Sequential number (each part has each own sequence).
> >> +
> >> + prev_id has either the same distribution as here_id (but with 3:8:21)
> >> + split, or one of two reserved values (-1) or (-2). Either case can
> >> + dominate depending on the workload.
> >> +*/
> >> +u32 ChainedOriginDepot::ChainedOriginDepotNode::hash(const args_type &args) {
> >> + const u32 m = 0x5bd1e995;
> >> + const u32 seed = 0x9747b28c;
> >> + const u32 r = 24;
> >> + u32 h = seed;
> >> + u32 k = args.here_id;
> >> + k *= m;
> >> + k ^= k >> r;
> >> + k *= m;
> >> + h *= m;
> >> + h ^= k;
> >> +
> >> + k = args.prev_id;
> >> + k *= m;
> >> + k ^= k >> r;
> >> + k *= m;
> >> + h *= m;
> >> + h ^= k;
> >> +
> >> + h ^= h >> 13;
> >> + h *= m;
> >> + h ^= h >> 15;
> >> + return h;
> >> +}
> >> +
> >> +bool ChainedOriginDepot::ChainedOriginDepotNode::is_valid(
> >> + const args_type &args) {
> >> + return true;
> >> +}
> >> +
> >> +void ChainedOriginDepot::ChainedOriginDepotNode::store(const args_type &args,
> >> + u32 other_hash) {
> >> + here_id = args.here_id;
> >> + prev_id = args.prev_id;
> >> +}
> >> +
> >> +ChainedOriginDepot::ChainedOriginDepotNode::args_type
> >> +ChainedOriginDepot::ChainedOriginDepotNode::load() const {
> >> + args_type ret = {here_id, prev_id};
> >> + return ret;
> >> +}
> >> +
> >> +ChainedOriginDepot::ChainedOriginDepotNode::Handle
> >> +ChainedOriginDepot::ChainedOriginDepotNode::get_handle() {
> >> + return Handle(this);
> >> +}
> >> +
> >> +ChainedOriginDepot::ChainedOriginDepot() {}
> >> +
> >> +StackDepotStats *ChainedOriginDepot::GetStats() { return depot.GetStats(); }
> >> +
> >> +bool ChainedOriginDepot::Put(u32 here_id, u32 prev_id, u32 *new_id) {
> >> + ChainedOriginDepotDesc desc = {here_id, prev_id};
> >> + bool inserted;
> >> + ChainedOriginDepotNode::Handle h = depot.Put(desc, &inserted);
> >> + *new_id = h.valid() ? h.id() : 0;
> >> + return inserted;
> >> +}
> >> +
> >> +u32 ChainedOriginDepot::Get(u32 id, u32 *other) {
> >> + ChainedOriginDepotDesc desc = depot.Get(id);
> >> + *other = desc.prev_id;
> >> + return desc.here_id;
> >> +}
> >> +
> >> +void ChainedOriginDepot::LockAll() { depot.LockAll(); }
> >> +
> >> +void ChainedOriginDepot::UnlockAll() { depot.UnlockAll(); }
> >> +
> >> +} // namespace __sanitizer
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_chained_origin_depot.h b/libsanitizer/sanitizer_common/sanitizer_chained_origin_depot.h
> >> new file mode 100644
> >> index 00000000000..453cdf6b544
> >> --- /dev/null
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_chained_origin_depot.h
> >> @@ -0,0 +1,88 @@
> >> +//===-- sanitizer_chained_origin_depot.h ------------------------*- C++ -*-===//
> >> +//
> >> +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
> >> +// See https://llvm.org/LICENSE.txt for license information.
> >> +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
> >> +//
> >> +//===----------------------------------------------------------------------===//
> >> +//
> >> +// A storage for chained origins.
> >> +//===----------------------------------------------------------------------===//
> >> +
> >> +#ifndef SANITIZER_CHAINED_ORIGIN_DEPOT_H
> >> +#define SANITIZER_CHAINED_ORIGIN_DEPOT_H
> >> +
> >> +#include "sanitizer_common.h"
> >> +#include "sanitizer_stackdepotbase.h"
> >> +
> >> +namespace __sanitizer {
> >> +
> >> +class ChainedOriginDepot {
> >> + public:
> >> + ChainedOriginDepot();
> >> +
> >> + // Gets the statistic of the origin chain storage.
> >> + StackDepotStats *GetStats();
> >> +
> >> + // Stores a chain with StackDepot ID here_id and previous chain ID prev_id.
> >> + // If successful, returns true and the new chain id new_id.
> >> + // If the same element already exists, returns false and sets new_id to the
> >> + // existing ID.
> >> + bool Put(u32 here_id, u32 prev_id, u32 *new_id);
> >> +
> >> + // Retrieves the stored StackDepot ID for the given origin ID.
> >> + u32 Get(u32 id, u32 *other);
> >> +
> >> + void LockAll();
> >> + void UnlockAll();
> >> +
> >> + private:
> >> + struct ChainedOriginDepotDesc {
> >> + u32 here_id;
> >> + u32 prev_id;
> >> + };
> >> +
> >> + struct ChainedOriginDepotNode {
> >> + ChainedOriginDepotNode *link;
> >> + u32 id;
> >> + u32 here_id;
> >> + u32 prev_id;
> >> +
> >> + typedef ChainedOriginDepotDesc args_type;
> >> +
> >> + bool eq(u32 hash, const args_type &args) const;
> >> +
> >> + static uptr storage_size(const args_type &args);
> >> +
> >> + static u32 hash(const args_type &args);
> >> +
> >> + static bool is_valid(const args_type &args);
> >> +
> >> + void store(const args_type &args, u32 other_hash);
> >> +
> >> + args_type load() const;
> >> +
> >> + struct Handle {
> >> + ChainedOriginDepotNode *node_;
> >> + Handle() : node_(nullptr) {}
> >> + explicit Handle(ChainedOriginDepotNode *node) : node_(node) {}
> >> + bool valid() { return node_; }
> >> + u32 id() { return node_->id; }
> >> + int here_id() { return node_->here_id; }
> >> + int prev_id() { return node_->prev_id; }
> >> + };
> >> +
> >> + Handle get_handle();
> >> +
> >> + typedef Handle handle_type;
> >> + };
> >> +
> >> + StackDepotBase<ChainedOriginDepotNode, 4, 20> depot;
> >> +
> >> + ChainedOriginDepot(const ChainedOriginDepot &) = delete;
> >> + void operator=(const ChainedOriginDepot &) = delete;
> >> +};
> >> +
> >> +} // namespace __sanitizer
> >> +
> >> +#endif // SANITIZER_CHAINED_ORIGIN_DEPOT_H
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_common.cpp b/libsanitizer/sanitizer_common/sanitizer_common.cpp
> >> index 87efda5bd37..33960d94a2f 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_common.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_common.cpp
> >> @@ -87,7 +87,7 @@ const char *StripModuleName(const char *module) {
> >> void ReportErrorSummary(const char *error_message, const char *alt_tool_name) {
> >> if (!common_flags()->print_summary)
> >> return;
> >> - InternalScopedString buff(kMaxSummaryLength);
> >> + InternalScopedString buff;
> >> buff.append("SUMMARY: %s: %s",
> >> alt_tool_name ? alt_tool_name : SanitizerToolName, error_message);
> >> __sanitizer_report_error_summary(buff.data());
> >> @@ -274,6 +274,14 @@ uptr ReadBinaryNameCached(/*out*/char *buf, uptr buf_len) {
> >> return name_len;
> >> }
> >>
> >> +uptr ReadBinaryDir(/*out*/ char *buf, uptr buf_len) {
> >> + ReadBinaryNameCached(buf, buf_len);
> >> + const char *exec_name_pos = StripModuleName(buf);
> >> + uptr name_len = exec_name_pos - buf;
> >> + buf[name_len] = '\0';
> >> + return name_len;
> >> +}
> >> +
> >> #if !SANITIZER_GO
> >> void PrintCmdline() {
> >> char **argv = GetArgv();
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_common.h b/libsanitizer/sanitizer_common/sanitizer_common.h
> >> index bce24d68045..7b65dd7dfb8 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_common.h
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_common.h
> >> @@ -44,7 +44,7 @@ const uptr kMaxPathLength = 4096;
> >>
> >> const uptr kMaxThreadStackSize = 1 << 30; // 1Gb
> >>
> >> -static const uptr kErrorMessageBufferSize = 1 << 16;
> >> +const uptr kErrorMessageBufferSize = 1 << 16;
> >>
> >> // Denotes fake PC values that come from JIT/JAVA/etc.
> >> // For such PC values __tsan_symbolize_external_ex() will be called.
> >> @@ -135,6 +135,15 @@ void UnmapFromTo(uptr from, uptr to);
> >> uptr MapDynamicShadow(uptr shadow_size_bytes, uptr shadow_scale,
> >> uptr min_shadow_base_alignment, uptr &high_mem_end);
> >>
> >> +// Let S = max(shadow_size, num_aliases * alias_size, ring_buffer_size).
> >> +// Reserves 2*S bytes of address space to the right of the returned address and
> >> +// ring_buffer_size bytes to the left. The returned address is aligned to 2*S.
> >> +// Also creates num_aliases regions of accessible memory starting at offset S
> >> +// from the returned address. Each region has size alias_size and is backed by
> >> +// the same physical memory.
> >> +uptr MapDynamicShadowAndAliases(uptr shadow_size, uptr alias_size,
> >> + uptr num_aliases, uptr ring_buffer_size);
> >> +
> >> // Reserve memory range [beg, end]. If madvise_shadow is true then apply
> >> // madvise (e.g. hugepages, core dumping) requested by options.
> >> void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name,
> >> @@ -248,6 +257,7 @@ const char *StripModuleName(const char *module);
> >> // OS
> >> uptr ReadBinaryName(/*out*/char *buf, uptr buf_len);
> >> uptr ReadBinaryNameCached(/*out*/char *buf, uptr buf_len);
> >> +uptr ReadBinaryDir(/*out*/ char *buf, uptr buf_len);
> >> uptr ReadLongProcessName(/*out*/ char *buf, uptr buf_len);
> >> const char *GetProcessName();
> >> void UpdateProcessName();
> >> @@ -294,8 +304,8 @@ void NORETURN ReportMmapFailureAndDie(uptr size, const char *mem_type,
> >> const char *mmap_type, error_t err,
> >> bool raw_report = false);
> >>
> >> -// Specific tools may override behavior of "Die" and "CheckFailed" functions
> >> -// to do tool-specific job.
> >> +// Specific tools may override behavior of "Die" function to do tool-specific
> >> +// job.
> >> typedef void (*DieCallbackType)(void);
> >>
> >> // It's possible to add several callbacks that would be run when "Die" is
> >> @@ -307,9 +317,7 @@ bool RemoveDieCallback(DieCallbackType callback);
> >>
> >> void SetUserDieCallback(DieCallbackType callback);
> >>
> >> -typedef void (*CheckFailedCallbackType)(const char *, int, const char *,
> >> - u64, u64);
> >> -void SetCheckFailedCallback(CheckFailedCallbackType callback);
> >> +void SetCheckUnwindCallback(void (*callback)());
> >>
> >> // Callback will be called if soft_rss_limit_mb is given and the limit is
> >> // exceeded (exceeded==true) or if rss went down below the limit
> >> @@ -343,8 +351,6 @@ void ReportDeadlySignal(const SignalContext &sig, u32 tid,
> >> void SetAlternateSignalStack();
> >> void UnsetAlternateSignalStack();
> >>
> >> -// 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.
> >> @@ -441,8 +447,14 @@ inline uptr Log2(uptr x) {
> >>
> >> // Don't use std::min, std::max or std::swap, to minimize dependency
> >> // on libstdc++.
> >> -template<class T> T Min(T a, T b) { return a < b ? a : b; }
> >> -template<class T> T Max(T a, T b) { return a > b ? a : b; }
> >> +template <class T>
> >> +constexpr T Min(T a, T b) {
> >> + return a < b ? a : b;
> >> +}
> >> +template <class T>
> >> +constexpr T Max(T a, T b) {
> >> + return a > b ? a : b;
> >> +}
> >> template<class T> void Swap(T& a, T& b) {
> >> T tmp = a;
> >> a = b;
> >> @@ -467,6 +479,7 @@ inline int ToLower(int c) {
> >> template<typename T>
> >> class InternalMmapVectorNoCtor {
> >> public:
> >> + using value_type = T;
> >> void Initialize(uptr initial_capacity) {
> >> capacity_bytes_ = 0;
> >> size_ = 0;
> >> @@ -590,21 +603,21 @@ class InternalMmapVector : public InternalMmapVectorNoCtor<T> {
> >> InternalMmapVector &operator=(InternalMmapVector &&) = delete;
> >> };
> >>
> >> -class InternalScopedString : public InternalMmapVector<char> {
> >> +class InternalScopedString {
> >> public:
> >> - explicit InternalScopedString(uptr max_length)
> >> - : InternalMmapVector<char>(max_length), length_(0) {
> >> - (*this)[0] = '\0';
> >> - }
> >> - uptr length() { return length_; }
> >> + InternalScopedString() : buffer_(1) { buffer_[0] = '\0'; }
> >> +
> >> + uptr length() const { return buffer_.size() - 1; }
> >> void clear() {
> >> - (*this)[0] = '\0';
> >> - length_ = 0;
> >> + buffer_.resize(1);
> >> + buffer_[0] = '\0';
> >> }
> >> void append(const char *format, ...);
> >> + const char *data() const { return buffer_.data(); }
> >> + char *data() { return buffer_.data(); }
> >>
> >> private:
> >> - uptr length_;
> >> + InternalMmapVector<char> buffer_;
> >> };
> >>
> >> template <class T>
> >> @@ -651,9 +664,13 @@ void Sort(T *v, uptr size, Compare comp = {}) {
> >>
> >> // Works like std::lower_bound: finds the first element that is not less
> >> // than the val.
> >> -template <class Container, class Value, class Compare>
> >> -uptr InternalLowerBound(const Container &v, uptr first, uptr last,
> >> - const Value &val, Compare comp) {
> >> +template <class Container,
> >> + class Compare = CompareLess<typename Container::value_type>>
> >> +uptr InternalLowerBound(const Container &v,
> >> + const typename Container::value_type &val,
> >> + Compare comp = {}) {
> >> + uptr first = 0;
> >> + uptr last = v.size();
> >> while (last > first) {
> >> uptr mid = (first + last) / 2;
> >> if (comp(v[mid], val))
> >> @@ -677,6 +694,27 @@ enum ModuleArch {
> >> kModuleArchRISCV64
> >> };
> >>
> >> +// Sorts and removes duplicates from the container.
> >> +template <class Container,
> >> + class Compare = CompareLess<typename Container::value_type>>
> >> +void SortAndDedup(Container &v, Compare comp = {}) {
> >> + Sort(v.data(), v.size(), comp);
> >> + uptr size = v.size();
> >> + if (size < 2)
> >> + return;
> >> + uptr last = 0;
> >> + for (uptr i = 1; i < size; ++i) {
> >> + if (comp(v[last], v[i])) {
> >> + ++last;
> >> + if (last != i)
> >> + v[last] = v[i];
> >> + } else {
> >> + CHECK(!comp(v[i], v[last]));
> >> + }
> >> + }
> >> + v.resize(last + 1);
> >> +}
> >> +
> >> // Opens the file 'file_name" and reads up to 'max_len' bytes.
> >> // The resulting buffer is mmaped and stored in '*buff'.
> >> // Returns true if file was successfully opened and read.
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc b/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc
> >> index 2f2787e283a..7867fccde39 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc
> >> @@ -239,7 +239,7 @@ extern const short *_tolower_tab_;
> >> COMMON_INTERCEPT_FUNCTION(fn)
> >> #endif
> >>
> >> -#ifdef __GLIBC__
> >> +#if SANITIZER_GLIBC
> >> // If we could not find the versioned symbol, fall back to an unversioned
> >> // lookup. This is needed to work around a GLibc bug that causes dlsym
> >> // with RTLD_NEXT to return the oldest versioned symbol.
> >> @@ -2195,6 +2195,7 @@ INTERCEPTOR(int, clock_gettime, u32 clk_id, void *tp) {
> >> }
> >> return res;
> >> }
> >> +#if SANITIZER_GLIBC
> >> namespace __sanitizer {
> >> extern "C" {
> >> int real_clock_gettime(u32 clk_id, void *tp) {
> >> @@ -2204,6 +2205,7 @@ int real_clock_gettime(u32 clk_id, void *tp) {
> >> }
> >> } // extern "C"
> >> } // namespace __sanitizer
> >> +#endif
> >> INTERCEPTOR(int, clock_settime, u32 clk_id, const void *tp) {
> >> void *ctx;
> >> COMMON_INTERCEPTOR_ENTER(ctx, clock_settime, clk_id, tp);
> >> @@ -3355,7 +3357,7 @@ INTERCEPTOR(char *, setlocale, int category, char *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);
> >> + COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, REAL(strlen)(res) + 1);
> >> unpoison_ctype_arrays(ctx);
> >> }
> >> return res;
> >> @@ -4030,7 +4032,7 @@ INTERCEPTOR(int, sigwait, __sanitizer_sigset_t *set, int *sig) {
> >> // FIXME: under ASan the call below may write to freed memory and corrupt
> >> // its metadata. See
> >> // https://github.com/google/sanitizers/issues/321.
> >> - int res = REAL(sigwait)(set, sig);
> >> + int res = COMMON_INTERCEPTOR_BLOCK_REAL(sigwait)(set, sig);
> >> if (!res && sig) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sig, sizeof(*sig));
> >> return res;
> >> }
> >> @@ -4047,7 +4049,7 @@ INTERCEPTOR(int, sigwaitinfo, __sanitizer_sigset_t *set, void *info) {
> >> // FIXME: under ASan the call below may write to freed memory and corrupt
> >> // its metadata. See
> >> // https://github.com/google/sanitizers/issues/321.
> >> - int res = REAL(sigwaitinfo)(set, info);
> >> + int res = COMMON_INTERCEPTOR_BLOCK_REAL(sigwaitinfo)(set, info);
> >> if (res > 0 && info) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, info, siginfo_t_sz);
> >> return res;
> >> }
> >> @@ -4066,7 +4068,7 @@ INTERCEPTOR(int, sigtimedwait, __sanitizer_sigset_t *set, void *info,
> >> // FIXME: under ASan the call below may write to freed memory and corrupt
> >> // its metadata. See
> >> // https://github.com/google/sanitizers/issues/321.
> >> - int res = REAL(sigtimedwait)(set, info, timeout);
> >> + int res = COMMON_INTERCEPTOR_BLOCK_REAL(sigtimedwait)(set, info, timeout);
> >> if (res > 0 && info) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, info, siginfo_t_sz);
> >> return res;
> >> }
> >> @@ -5995,6 +5997,9 @@ void unpoison_file(__sanitizer_FILE *fp) {
> >> if (fp->_IO_read_base && fp->_IO_read_base < fp->_IO_read_end)
> >> COMMON_INTERCEPTOR_INITIALIZE_RANGE(fp->_IO_read_base,
> >> fp->_IO_read_end - fp->_IO_read_base);
> >> + if (fp->_IO_write_base && fp->_IO_write_base < fp->_IO_write_end)
> >> + COMMON_INTERCEPTOR_INITIALIZE_RANGE(fp->_IO_write_base,
> >> + fp->_IO_write_end - fp->_IO_write_base);
> >> #endif
> >> #endif // SANITIZER_HAS_STRUCT_FILE
> >> }
> >> @@ -6221,6 +6226,8 @@ INTERCEPTOR(void, _obstack_newchunk, __sanitizer_obstack *obstack, int length) {
> >> INTERCEPTOR(int, fflush, __sanitizer_FILE *fp) {
> >> void *ctx;
> >> COMMON_INTERCEPTOR_ENTER(ctx, fflush, fp);
> >> + if (fp)
> >> + unpoison_file(fp);
> >> int res = REAL(fflush)(fp);
> >> // FIXME: handle fp == NULL
> >> if (fp) {
> >> @@ -6240,6 +6247,8 @@ INTERCEPTOR(int, fclose, __sanitizer_FILE *fp) {
> >> COMMON_INTERCEPTOR_ENTER(ctx, fclose, fp);
> >> COMMON_INTERCEPTOR_FILE_CLOSE(ctx, fp);
> >> const FileMetadata *m = GetInterceptorMetadata(fp);
> >> + if (fp)
> >> + unpoison_file(fp);
> >> int res = REAL(fclose)(fp);
> >> if (m) {
> >> COMMON_INTERCEPTOR_INITIALIZE_RANGE(*m->addr, *m->size);
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_common_interceptors_ioctl.inc b/libsanitizer/sanitizer_common/sanitizer_common_interceptors_ioctl.inc
> >> index 490a04b2181..7f181258eab 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_common_interceptors_ioctl.inc
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_common_interceptors_ioctl.inc
> >> @@ -330,13 +330,17 @@ static void ioctl_table_fill() {
> >> _(SOUND_PCM_WRITE_CHANNELS, WRITE, sizeof(int));
> >> _(SOUND_PCM_WRITE_FILTER, WRITE, sizeof(int));
> >> _(TCFLSH, NONE, 0);
> >> +#if SANITIZER_GLIBC
> >> _(TCGETA, WRITE, struct_termio_sz);
> >> +#endif
> >> _(TCGETS, WRITE, struct_termios_sz);
> >> _(TCSBRK, NONE, 0);
> >> _(TCSBRKP, NONE, 0);
> >> +#if SANITIZER_GLIBC
> >> _(TCSETA, READ, struct_termio_sz);
> >> _(TCSETAF, READ, struct_termio_sz);
> >> _(TCSETAW, READ, struct_termio_sz);
> >> +#endif
> >> _(TCSETS, READ, struct_termios_sz);
> >> _(TCSETSF, READ, struct_termios_sz);
> >> _(TCSETSW, READ, struct_termios_sz);
> >> @@ -364,7 +368,7 @@ static void ioctl_table_fill() {
> >> _(VT_WAITACTIVE, NONE, 0);
> >> #endif
> >>
> >> -#if SANITIZER_LINUX && !SANITIZER_ANDROID
> >> +#if SANITIZER_GLIBC
> >> // _(SIOCDEVPLIP, WRITE, struct_ifreq_sz); // the same as EQL_ENSLAVE
> >> _(CYGETDEFTHRESH, WRITE, sizeof(int));
> >> _(CYGETDEFTIMEOUT, WRITE, sizeof(int));
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_common_interceptors_vfork_aarch64.inc.S b/libsanitizer/sanitizer_common/sanitizer_common_interceptors_vfork_aarch64.inc.S
> >> index 20f42f1ea94..72e482754b6 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_common_interceptors_vfork_aarch64.inc.S
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_common_interceptors_vfork_aarch64.inc.S
> >> @@ -1,6 +1,7 @@
> >> #if defined(__aarch64__) && defined(__linux__)
> >>
> >> #include "sanitizer_common/sanitizer_asm.h"
> >> +#include "builtins/assembly.h"
> >>
> >> ASM_HIDDEN(COMMON_INTERCEPTOR_SPILL_AREA)
> >>
> >> @@ -9,6 +10,7 @@ ASM_HIDDEN(COMMON_INTERCEPTOR_SPILL_AREA)
> >> ASM_TYPE_FUNCTION(ASM_WRAPPER_NAME(vfork))
> >> ASM_WRAPPER_NAME(vfork):
> >> // Save x30 in the off-stack spill area.
> >> + hint #25 // paciasp
> >> stp xzr, x30, [sp, #-16]!
> >> bl COMMON_INTERCEPTOR_SPILL_AREA
> >> ldp xzr, x30, [sp], 16
> >> @@ -33,6 +35,7 @@ ASM_WRAPPER_NAME(vfork):
> >> bl COMMON_INTERCEPTOR_SPILL_AREA
> >> ldr x30, [x0]
> >> ldp x0, xzr, [sp], 16
> >> + hint #29 // autiasp
> >>
> >> ret
> >> ASM_SIZE(vfork)
> >> @@ -40,4 +43,6 @@ ASM_SIZE(vfork)
> >> .weak vfork
> >> .set vfork, ASM_WRAPPER_NAME(vfork)
> >>
> >> +GNU_PROPERTY_BTI_PAC
> >> +
> >> #endif
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_common_interface.inc b/libsanitizer/sanitizer_common/sanitizer_common_interface.inc
> >> index c78b6e10b68..932e5478616 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_common_interface.inc
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_common_interface.inc
> >> @@ -13,6 +13,7 @@ INTERFACE_FUNCTION(__sanitizer_contiguous_container_find_bad_address)
> >> INTERFACE_FUNCTION(__sanitizer_set_death_callback)
> >> INTERFACE_FUNCTION(__sanitizer_set_report_path)
> >> INTERFACE_FUNCTION(__sanitizer_set_report_fd)
> >> +INTERFACE_FUNCTION(__sanitizer_get_report_path)
> >> INTERFACE_FUNCTION(__sanitizer_verify_contiguous_container)
> >> INTERFACE_WEAK_FUNCTION(__sanitizer_on_print)
> >> INTERFACE_WEAK_FUNCTION(__sanitizer_report_error_summary)
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_common_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_common_libcdep.cpp
> >> index 047c5a17ea6..1037938f3d3 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_common_libcdep.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_common_libcdep.cpp
> >> @@ -92,14 +92,13 @@ void *BackgroundThread(void *arg) {
> >> #endif
> >>
> >> void WriteToSyslog(const char *msg) {
> >> - InternalScopedString msg_copy(kErrorMessageBufferSize);
> >> + InternalScopedString msg_copy;
> >> msg_copy.append("%s", msg);
> >> - char *p = msg_copy.data();
> >> - char *q;
> >> + const char *p = msg_copy.data();
> >>
> >> // Print one line at a time.
> >> // syslog, at least on Android, has an implicit message length limit.
> >> - while ((q = internal_strchr(p, '\n'))) {
> >> + while (char* q = internal_strchr(p, '\n')) {
> >> *q = '\0';
> >> WriteOneLineToSyslog(p);
> >> p = q + 1;
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_file.cpp b/libsanitizer/sanitizer_common/sanitizer_file.cpp
> >> index 7cce60906b7..0b92dccde4a 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_file.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_file.cpp
> >> @@ -58,6 +58,9 @@ void ReportFile::ReopenIfNecessary() {
> >> } else {
> >> internal_snprintf(full_path, kMaxPathLength, "%s.%zu", path_prefix, pid);
> >> }
> >> + if (common_flags()->log_suffix) {
> >> + internal_strlcat(full_path, common_flags()->log_suffix, kMaxPathLength);
> >> + }
> >> error_t err;
> >> fd = OpenFile(full_path, WrOnly, &err);
> >> if (fd == kInvalidFd) {
> >> @@ -95,6 +98,12 @@ void ReportFile::SetReportPath(const char *path) {
> >> }
> >> }
> >>
> >> +const char *ReportFile::GetReportPath() {
> >> + SpinMutexLock l(mu);
> >> + ReopenIfNecessary();
> >> + return full_path;
> >> +}
> >> +
> >> bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size,
> >> uptr *read_len, uptr max_len, error_t *errno_p) {
> >> *buff = nullptr;
> >> @@ -213,6 +222,10 @@ void __sanitizer_set_report_fd(void *fd) {
> >> report_file.fd = (fd_t)reinterpret_cast<uptr>(fd);
> >> report_file.fd_pid = internal_getpid();
> >> }
> >> +
> >> +const char *__sanitizer_get_report_path() {
> >> + return report_file.GetReportPath();
> >> +}
> >> } // extern "C"
> >>
> >> #endif // !SANITIZER_FUCHSIA
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_file.h b/libsanitizer/sanitizer_common/sanitizer_file.h
> >> index 26681f0493d..08671ab67d0 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_file.h
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_file.h
> >> @@ -26,6 +26,7 @@ struct ReportFile {
> >> void Write(const char *buffer, uptr length);
> >> bool SupportsColors();
> >> void SetReportPath(const char *path);
> >> + const char *GetReportPath();
> >>
> >> // Don't use fields directly. They are only declared public to allow
> >> // aggregate initialization.
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_flags.cpp b/libsanitizer/sanitizer_common/sanitizer_flags.cpp
> >> index 21048be7304..d52e96a7c38 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_flags.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_flags.cpp
> >> @@ -35,6 +35,7 @@ void CommonFlags::CopyFrom(const CommonFlags &other) {
> >> // Copy the string from "s" to "out", making the following substitutions:
> >> // %b = binary basename
> >> // %p = pid
> >> +// %d = binary directory
> >> void SubstituteForFlagValue(const char *s, char *out, uptr out_size) {
> >> char *out_end = out + out_size;
> >> while (*s && out < out_end - 1) {
> >> @@ -64,6 +65,12 @@ void SubstituteForFlagValue(const char *s, char *out, uptr out_size) {
> >> s += 2; // skip "%p"
> >> break;
> >> }
> >> + case 'd': {
> >> + uptr len = ReadBinaryDir(out, out_end - out);
> >> + out += len;
> >> + s += 2; // skip "%d"
> >> + break;
> >> + }
> >> default:
> >> *out++ = *s++;
> >> break;
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_flags.inc b/libsanitizer/sanitizer_common/sanitizer_flags.inc
> >> index cfb5822645f..3bc44c6b1eb 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_flags.inc
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_flags.inc
> >> @@ -59,6 +59,8 @@ COMMON_FLAG(
> >> bool, log_exe_name, false,
> >> "Mention name of executable when reporting error and "
> >> "append executable name to logs (as in \"log_path.exe_name.pid\").")
> >> +COMMON_FLAG(const char *, log_suffix, nullptr,
> >> + "String to append to log file name, e.g. \".txt\".")
> >> COMMON_FLAG(
> >> bool, log_to_syslog, (bool)SANITIZER_ANDROID || (bool)SANITIZER_MAC,
> >> "Write all sanitizer output to syslog in addition to other means of "
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_fuchsia.cpp b/libsanitizer/sanitizer_common/sanitizer_fuchsia.cpp
> >> index 7200ffdac0f..4f692f99c20 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_fuchsia.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_fuchsia.cpp
> >> @@ -14,7 +14,6 @@
> >> #include "sanitizer_fuchsia.h"
> >> #if SANITIZER_FUCHSIA
> >>
> >> -#include <limits.h>
> >> #include <pthread.h>
> >> #include <stdlib.h>
> >> #include <unistd.h>
> >> @@ -69,9 +68,7 @@ uptr internal_getpid() {
> >> return pid;
> >> }
> >>
> >> -int internal_dlinfo(void *handle, int request, void *p) {
> >> - UNIMPLEMENTED();
> >> -}
> >> +int internal_dlinfo(void *handle, int request, void *p) { UNIMPLEMENTED(); }
> >>
> >> uptr GetThreadSelf() { return reinterpret_cast<uptr>(thrd_current()); }
> >>
> >> @@ -153,9 +150,9 @@ void BlockingMutex::CheckLocked() {
> >> CHECK_NE(MtxUnlocked, atomic_load(m, memory_order_relaxed));
> >> }
> >>
> >> -uptr GetPageSize() { return PAGE_SIZE; }
> >> +uptr GetPageSize() { return _zx_system_get_page_size(); }
> >>
> >> -uptr GetMmapGranularity() { return PAGE_SIZE; }
> >> +uptr GetMmapGranularity() { return _zx_system_get_page_size(); }
> >>
> >> sanitizer_shadow_bounds_t ShadowBounds;
> >>
> >> @@ -168,7 +165,7 @@ uptr GetMaxVirtualAddress() { return GetMaxUserVirtualAddress(); }
> >>
> >> static void *DoAnonymousMmapOrDie(uptr size, const char *mem_type,
> >> bool raw_report, bool die_for_nomem) {
> >> - size = RoundUpTo(size, PAGE_SIZE);
> >> + size = RoundUpTo(size, GetPageSize());
> >>
> >> zx_handle_t vmo;
> >> zx_status_t status = _zx_vmo_create(size, 0, &vmo);
> >> @@ -214,15 +211,14 @@ void *MmapOrDieOnFatalError(uptr size, const char *mem_type) {
> >>
> >> uptr ReservedAddressRange::Init(uptr init_size, const char *name,
> >> uptr fixed_addr) {
> >> - init_size = RoundUpTo(init_size, PAGE_SIZE);
> >> + init_size = RoundUpTo(init_size, GetPageSize());
> >> DCHECK_EQ(os_handle_, ZX_HANDLE_INVALID);
> >> uintptr_t base;
> >> zx_handle_t vmar;
> >> - zx_status_t status =
> >> - _zx_vmar_allocate(
> >> - _zx_vmar_root_self(),
> >> - ZX_VM_CAN_MAP_READ | ZX_VM_CAN_MAP_WRITE | ZX_VM_CAN_MAP_SPECIFIC,
> >> - 0, init_size, &vmar, &base);
> >> + zx_status_t status = _zx_vmar_allocate(
> >> + _zx_vmar_root_self(),
> >> + ZX_VM_CAN_MAP_READ | ZX_VM_CAN_MAP_WRITE | ZX_VM_CAN_MAP_SPECIFIC, 0,
> >> + init_size, &vmar, &base);
> >> if (status != ZX_OK)
> >> ReportMmapFailureAndDie(init_size, name, "zx_vmar_allocate", status);
> >> base_ = reinterpret_cast<void *>(base);
> >> @@ -236,7 +232,7 @@ uptr ReservedAddressRange::Init(uptr init_size, const char *name,
> >> static uptr DoMmapFixedOrDie(zx_handle_t vmar, uptr fixed_addr, uptr map_size,
> >> void *base, const char *name, bool die_for_nomem) {
> >> uptr offset = fixed_addr - reinterpret_cast<uptr>(base);
> >> - map_size = RoundUpTo(map_size, PAGE_SIZE);
> >> + map_size = RoundUpTo(map_size, GetPageSize());
> >> zx_handle_t vmo;
> >> zx_status_t status = _zx_vmo_create(map_size, 0, &vmo);
> >> if (status != ZX_OK) {
> >> @@ -264,19 +260,19 @@ static uptr DoMmapFixedOrDie(zx_handle_t vmar, uptr fixed_addr, uptr map_size,
> >>
> >> uptr ReservedAddressRange::Map(uptr fixed_addr, uptr map_size,
> >> const char *name) {
> >> - return DoMmapFixedOrDie(os_handle_, fixed_addr, map_size, base_,
> >> - name_, false);
> >> + return DoMmapFixedOrDie(os_handle_, fixed_addr, map_size, base_, name_,
> >> + false);
> >> }
> >>
> >> uptr ReservedAddressRange::MapOrDie(uptr fixed_addr, uptr map_size,
> >> const char *name) {
> >> - return DoMmapFixedOrDie(os_handle_, fixed_addr, map_size, base_,
> >> - name_, true);
> >> + return DoMmapFixedOrDie(os_handle_, fixed_addr, map_size, base_, name_, true);
> >> }
> >>
> >> void UnmapOrDieVmar(void *addr, uptr size, zx_handle_t target_vmar) {
> >> - if (!addr || !size) return;
> >> - size = RoundUpTo(size, PAGE_SIZE);
> >> + if (!addr || !size)
> >> + return;
> >> + size = RoundUpTo(size, GetPageSize());
> >>
> >> zx_status_t status =
> >> _zx_vmar_unmap(target_vmar, reinterpret_cast<uintptr_t>(addr), size);
> >> @@ -316,7 +312,7 @@ void *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name) {
> >>
> >> void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment,
> >> const char *mem_type) {
> >> - CHECK_GE(size, PAGE_SIZE);
> >> + CHECK_GE(size, GetPageSize());
> >> CHECK(IsPowerOfTwo(size));
> >> CHECK(IsPowerOfTwo(alignment));
> >>
> >> @@ -356,7 +352,8 @@ void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment,
> >> _zx_vmar_root_self(),
> >> ZX_VM_PERM_READ | ZX_VM_PERM_WRITE | ZX_VM_SPECIFIC_OVERWRITE,
> >> addr - info.base, vmo, 0, size, &new_addr);
> >> - if (status == ZX_OK) CHECK_EQ(new_addr, addr);
> >> + if (status == ZX_OK)
> >> + CHECK_EQ(new_addr, addr);
> >> }
> >> }
> >> if (status == ZX_OK && addr != map_addr)
> >> @@ -381,9 +378,18 @@ void UnmapOrDie(void *addr, uptr size) {
> >> UnmapOrDieVmar(addr, size, _zx_vmar_root_self());
> >> }
> >>
> >> -// This is used on the shadow mapping, which cannot be changed.
> >> -// Zircon doesn't have anything like MADV_DONTNEED.
> >> -void ReleaseMemoryPagesToOS(uptr beg, uptr end) {}
> >> +void ReleaseMemoryPagesToOS(uptr beg, uptr end) {
> >> + uptr beg_aligned = RoundUpTo(beg, GetPageSize());
> >> + uptr end_aligned = RoundDownTo(end, GetPageSize());
> >> + if (beg_aligned < end_aligned) {
> >> + zx_handle_t root_vmar = _zx_vmar_root_self();
> >> + CHECK_NE(root_vmar, ZX_HANDLE_INVALID);
> >> + zx_status_t status =
> >> + _zx_vmar_op_range(root_vmar, ZX_VMAR_OP_DECOMMIT, beg_aligned,
> >> + end_aligned - beg_aligned, nullptr, 0);
> >> + CHECK_EQ(status, ZX_OK);
> >> + }
> >> +}
> >>
> >> void DumpProcessMap() {
> >> // TODO(mcgrathr): write it
> >> @@ -412,8 +418,9 @@ bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size,
> >> uint64_t vmo_size;
> >> status = _zx_vmo_get_size(vmo, &vmo_size);
> >> if (status == ZX_OK) {
> >> - if (vmo_size < max_len) max_len = vmo_size;
> >> - size_t map_size = RoundUpTo(max_len, PAGE_SIZE);
> >> + if (vmo_size < max_len)
> >> + max_len = vmo_size;
> >> + size_t map_size = RoundUpTo(max_len, GetPageSize());
> >> uintptr_t addr;
> >> status = _zx_vmar_map(_zx_vmar_root_self(), ZX_VM_PERM_READ, 0, vmo, 0,
> >> map_size, &addr);
> >> @@ -425,7 +432,8 @@ bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size,
> >> }
> >> _zx_handle_close(vmo);
> >> }
> >> - if (status != ZX_OK && errno_p) *errno_p = status;
> >> + if (status != ZX_OK && errno_p)
> >> + *errno_p = status;
> >> return status == ZX_OK;
> >> }
> >>
> >> @@ -499,9 +507,7 @@ bool GetRandom(void *buffer, uptr length, bool blocking) {
> >> return true;
> >> }
> >>
> >> -u32 GetNumberOfCPUs() {
> >> - return zx_system_get_num_cpus();
> >> -}
> >> +u32 GetNumberOfCPUs() { return zx_system_get_num_cpus(); }
> >>
> >> uptr GetRSS() { UNIMPLEMENTED(); }
> >>
> >> @@ -529,6 +535,10 @@ void __sanitizer_set_report_path(const char *path) {
> >> void __sanitizer_set_report_fd(void *fd) {
> >> UNREACHABLE("not available on Fuchsia");
> >> }
> >> +
> >> +const char *__sanitizer_get_report_path() {
> >> + UNREACHABLE("not available on Fuchsia");
> >> +}
> >> } // extern "C"
> >>
> >> #endif // SANITIZER_FUCHSIA
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_interface_internal.h b/libsanitizer/sanitizer_common/sanitizer_interface_internal.h
> >> index be8023e9e16..0b001c1c483 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_interface_internal.h
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_interface_internal.h
> >> @@ -28,6 +28,10 @@ extern "C" {
> >> // (casted to void *).
> >> SANITIZER_INTERFACE_ATTRIBUTE
> >> void __sanitizer_set_report_fd(void *fd);
> >> + // Get the current full report file path, if a path was specified by
> >> + // an earlier call to __sanitizer_set_report_path. Returns null otherwise.
> >> + SANITIZER_INTERFACE_ATTRIBUTE
> >> + const char *__sanitizer_get_report_path();
> >>
> >> typedef struct {
> >> int coverage_sandboxed;
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_internal_defs.h b/libsanitizer/sanitizer_common/sanitizer_internal_defs.h
> >> index d8f0540037d..84053fec264 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_internal_defs.h
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_internal_defs.h
> >> @@ -409,6 +409,9 @@ inline void Trap() {
> >> (void)enable_fp; \
> >> } while (0)
> >>
> >> +constexpr u32 kInvalidTid = -1;
> >> +constexpr u32 kMainTid = 0;
> >> +
> >> } // namespace __sanitizer
> >>
> >> namespace __asan {
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_libignore.cpp b/libsanitizer/sanitizer_common/sanitizer_libignore.cpp
> >> index 9ea19bc21fa..a65d3d896e3 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_libignore.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_libignore.cpp
> >> @@ -38,7 +38,7 @@ void LibIgnore::AddIgnoredLibrary(const char *name_templ) {
> >> void LibIgnore::OnLibraryLoaded(const char *name) {
> >> BlockingMutexLock lock(&mutex_);
> >> // Try to match suppressions with symlink target.
> >> - InternalScopedString buf(kMaxPathLength);
> >> + InternalMmapVector<char> buf(kMaxPathLength);
> >> if (name && internal_readlink(name, buf.data(), buf.size() - 1) > 0 &&
> >> buf[0]) {
> >> for (uptr i = 0; i < count_; i++) {
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_linux.cpp b/libsanitizer/sanitizer_common/sanitizer_linux.cpp
> >> index 379f6d9e294..b371477755f 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_linux.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_linux.cpp
> >> @@ -183,6 +183,14 @@ uptr internal_munmap(void *addr, uptr length) {
> >> return internal_syscall(SYSCALL(munmap), (uptr)addr, length);
> >> }
> >>
> >> +#if SANITIZER_LINUX
> >> +uptr internal_mremap(void *old_address, uptr old_size, uptr new_size, int flags,
> >> + void *new_address) {
> >> + return internal_syscall(SYSCALL(mremap), (uptr)old_address, old_size,
> >> + new_size, flags, (uptr)new_address);
> >> +}
> >> +#endif
> >> +
> >> int internal_mprotect(void *addr, uptr length, int prot) {
> >> return internal_syscall(SYSCALL(mprotect), (uptr)addr, length, prot);
> >> }
> >> @@ -489,22 +497,24 @@ int TgKill(pid_t pid, tid_t tid, int sig) {
> >> }
> >> #endif
> >>
> >> -#if !SANITIZER_SOLARIS && !SANITIZER_NETBSD
> >> +#if SANITIZER_GLIBC
> >> u64 NanoTime() {
> >> -#if SANITIZER_FREEBSD
> >> - timeval tv;
> >> -#else
> >> kernel_timeval tv;
> >> -#endif
> >> internal_memset(&tv, 0, sizeof(tv));
> >> internal_syscall(SYSCALL(gettimeofday), &tv, 0);
> >> - return (u64)tv.tv_sec * 1000*1000*1000 + tv.tv_usec * 1000;
> >> + return (u64)tv.tv_sec * 1000 * 1000 * 1000 + tv.tv_usec * 1000;
> >> }
> >> -
> >> +// Used by real_clock_gettime.
> >> uptr internal_clock_gettime(__sanitizer_clockid_t clk_id, void *tp) {
> >> return internal_syscall(SYSCALL(clock_gettime), clk_id, tp);
> >> }
> >> -#endif // !SANITIZER_SOLARIS && !SANITIZER_NETBSD
> >> +#elif !SANITIZER_SOLARIS && !SANITIZER_NETBSD
> >> +u64 NanoTime() {
> >> + struct timespec ts;
> >> + clock_gettime(CLOCK_REALTIME, &ts);
> >> + return (u64)ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
> >> +}
> >> +#endif
> >>
> >> // Like getenv, but reads env directly from /proc (on Linux) or parses the
> >> // 'environ' array (on some others) and does not use libc. This function
> >> @@ -1334,50 +1344,42 @@ uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
> >> #elif SANITIZER_RISCV64
> >> uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
> >> int *parent_tidptr, void *newtls, int *child_tidptr) {
> >> - long long res;
> >> if (!fn || !child_stack)
> >> return -EINVAL;
> >> +
> >> CHECK_EQ(0, (uptr)child_stack % 16);
> >> - 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 int (*__fn)(void *) __asm__("a0") = fn;
> >> + register int res __asm__("a0");
> >> + register int __flags __asm__("a0") = flags;
> >> register void *__stack __asm__("a1") = child_stack;
> >> - register int __flags __asm__("a2") = flags;
> >> - register void *__arg __asm__("a3") = arg;
> >> - register int *__ptid __asm__("a4") = parent_tidptr;
> >> - register void *__tls __asm__("a5") = newtls;
> >> - register int *__ctid __asm__("a6") = child_tidptr;
> >> + register int *__ptid __asm__("a2") = parent_tidptr;
> >> + register void *__tls __asm__("a3") = newtls;
> >> + register int *__ctid __asm__("a4") = child_tidptr;
> >> + register int (*__fn)(void *) __asm__("a5") = fn;
> >> + register void *__arg __asm__("a6") = arg;
> >> + register int nr_clone __asm__("a7") = __NR_clone;
> >>
> >> __asm__ __volatile__(
> >> - "mv a0,a2\n" /* flags */
> >> - "mv a2,a4\n" /* ptid */
> >> - "mv a3,a5\n" /* tls */
> >> - "mv a4,a6\n" /* ctid */
> >> - "addi a7, zero, %9\n" /* clone */
> >> -
> >> "ecall\n"
> >>
> >> - /* if (%r0 != 0)
> >> - * return %r0;
> >> + /* if (a0 != 0)
> >> + * return a0;
> >> */
> >> "bnez a0, 1f\n"
> >>
> >> - /* In the child, now. Call "fn(arg)". */
> >> - "ld a0, 8(sp)\n"
> >> - "ld a1, 16(sp)\n"
> >> - "jalr a1\n"
> >> + // In the child, now. Call "fn(arg)".
> >> + "mv a0, a6\n"
> >> + "jalr a5\n"
> >>
> >> - /* Call _exit(%r0). */
> >> - "addi a7, zero, %10\n"
> >> + // Call _exit(a0).
> >> + "addi a7, zero, %9\n"
> >> "ecall\n"
> >> "1:\n"
> >>
> >> : "=r"(res)
> >> - : "i"(-EINVAL), "r"(__fn), "r"(__stack), "r"(__flags), "r"(__arg),
> >> - "r"(__ptid), "r"(__tls), "r"(__ctid), "i"(__NR_clone), "i"(__NR_exit)
> >> - : "ra", "memory");
> >> + : "0"(__flags), "r"(__stack), "r"(__ptid), "r"(__tls), "r"(__ctid),
> >> + "r"(__fn), "r"(__arg), "r"(nr_clone), "i"(__NR_exit)
> >> + : "memory");
> >> return res;
> >> }
> >> #elif defined(__aarch64__)
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_linux.h b/libsanitizer/sanitizer_common/sanitizer_linux.h
> >> index 24902d1b6bc..9a23fcfb3b9 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_linux.h
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_linux.h
> >> @@ -49,7 +49,9 @@ uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count);
> >> uptr internal_sigaltstack(const void* ss, void* oss);
> >> uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set,
> >> __sanitizer_sigset_t *oldset);
> >> +#if SANITIZER_GLIBC
> >> uptr internal_clock_gettime(__sanitizer_clockid_t clk_id, void *tp);
> >> +#endif
> >>
> >> // Linux-only syscalls.
> >> #if SANITIZER_LINUX
> >> @@ -96,7 +98,6 @@ class ThreadLister {
> >> // Exposed for testing.
> >> uptr ThreadDescriptorSize();
> >> uptr ThreadSelf();
> >> -uptr ThreadSelfOffset();
> >>
> >> // Matches a library's file name against a base name (stripping path and version
> >> // information).
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp
> >> index bc10e89b1ed..572aa86fa53 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp
> >> @@ -36,6 +36,7 @@
> >> #include <link.h>
> >> #include <pthread.h>
> >> #include <signal.h>
> >> +#include <sys/mman.h>
> >> #include <sys/resource.h>
> >> #include <syslog.h>
> >>
> >> @@ -48,6 +49,10 @@
> >> #include <osreldate.h>
> >> #include <sys/sysctl.h>
> >> #define pthread_getattr_np pthread_attr_get_np
> >> +// The MAP_NORESERVE define has been removed in FreeBSD 11.x, and even before
> >> +// that, it was never implemented. So just define it to zero.
> >> +#undef MAP_NORESERVE
> >> +#define MAP_NORESERVE 0
> >> #endif
> >>
> >> #if SANITIZER_NETBSD
> >> @@ -183,85 +188,35 @@ __attribute__((unused)) static bool GetLibcVersion(int *major, int *minor,
> >> #endif
> >> }
> >>
> >> -#if !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_GO && \
> >> - !SANITIZER_NETBSD && !SANITIZER_SOLARIS
> >> -static uptr g_tls_size;
> >> +// True if we can use dlpi_tls_data. glibc before 2.25 may leave NULL (BZ
> >> +// #19826) so dlpi_tls_data cannot be used.
> >> +//
> >> +// musl before 1.2.3 and FreeBSD as of 12.2 incorrectly set dlpi_tls_data to
> >> +// the TLS initialization image
> >> +// https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=254774
> >> +__attribute__((unused)) static int g_use_dlpi_tls_data;
> >>
> >> -#ifdef __i386__
> >> -#define CHECK_GET_TLS_STATIC_INFO_VERSION (!__GLIBC_PREREQ(2, 27))
> >> -#else
> >> -#define CHECK_GET_TLS_STATIC_INFO_VERSION 0
> >> -#endif
> >> +#if SANITIZER_GLIBC && !SANITIZER_GO
> >> +__attribute__((unused)) static uptr g_tls_size;
> >> +void InitTlsSize() {
> >> + int major, minor, patch;
> >> + g_use_dlpi_tls_data =
> >> + GetLibcVersion(&major, &minor, &patch) && major == 2 && minor >= 25;
> >>
> >> -#if CHECK_GET_TLS_STATIC_INFO_VERSION
> >> -#define DL_INTERNAL_FUNCTION __attribute__((regparm(3), stdcall))
> >> -#else
> >> -#define DL_INTERNAL_FUNCTION
> >> +#if defined(__x86_64__) || defined(__powerpc64__)
> >> + void *get_tls_static_info = dlsym(RTLD_NEXT, "_dl_get_tls_static_info");
> >> + size_t tls_align;
> >> + ((void (*)(size_t *, size_t *))get_tls_static_info)(&g_tls_size, &tls_align);
> >> #endif
> >> -
> >> -namespace {
> >> -struct GetTlsStaticInfoCall {
> >> - typedef void (*get_tls_func)(size_t*, size_t*);
> >> -};
> >> -struct GetTlsStaticInfoRegparmCall {
> >> - typedef void (*get_tls_func)(size_t*, size_t*) DL_INTERNAL_FUNCTION;
> >> -};
> >> -
> >> -template <typename T>
> >> -void CallGetTls(void* ptr, size_t* size, size_t* align) {
> >> - typename T::get_tls_func get_tls;
> >> - CHECK_EQ(sizeof(get_tls), sizeof(ptr));
> >> - internal_memcpy(&get_tls, &ptr, sizeof(ptr));
> >> - CHECK_NE(get_tls, 0);
> >> - get_tls(size, align);
> >> -}
> >> -
> >> -bool CmpLibcVersion(int major, int minor, int patch) {
> >> - int ma;
> >> - int mi;
> >> - int pa;
> >> - if (!GetLibcVersion(&ma, &mi, &pa))
> >> - return false;
> >> - if (ma > major)
> >> - return true;
> >> - if (ma < major)
> >> - return false;
> >> - if (mi > minor)
> >> - return true;
> >> - if (mi < minor)
> >> - return false;
> >> - return pa >= patch;
> >> -}
> >> -
> >> -} // namespace
> >> -
> >> -void InitTlsSize() {
> >> - // all current supported platforms have 16 bytes stack alignment
> >> - const size_t kStackAlign = 16;
> >> - void *get_tls_static_info_ptr = dlsym(RTLD_NEXT, "_dl_get_tls_static_info");
> >> - size_t tls_size = 0;
> >> - size_t tls_align = 0;
> >> - // On i?86, _dl_get_tls_static_info used to be internal_function, i.e.
> >> - // __attribute__((regparm(3), stdcall)) before glibc 2.27 and is normal
> >> - // function in 2.27 and later.
> >> - if (CHECK_GET_TLS_STATIC_INFO_VERSION && !CmpLibcVersion(2, 27, 0))
> >> - CallGetTls<GetTlsStaticInfoRegparmCall>(get_tls_static_info_ptr,
> >> - &tls_size, &tls_align);
> >> - else
> >> - CallGetTls<GetTlsStaticInfoCall>(get_tls_static_info_ptr,
> >> - &tls_size, &tls_align);
> >> - if (tls_align < kStackAlign)
> >> - tls_align = kStackAlign;
> >> - g_tls_size = RoundUpTo(tls_size, tls_align);
> >> }
> >> #else
> >> void InitTlsSize() { }
> >> -#endif
> >> +#endif // SANITIZER_GLIBC && !SANITIZER_GO
> >>
> >> -#if (defined(__x86_64__) || defined(__i386__) || defined(__mips__) || \
> >> - defined(__aarch64__) || defined(__powerpc64__) || defined(__s390__) || \
> >> - defined(__arm__) || SANITIZER_RISCV64) && \
> >> - SANITIZER_LINUX && !SANITIZER_ANDROID
> >> +// On glibc x86_64, ThreadDescriptorSize() needs to be precise due to the usage
> >> +// of g_tls_size. On other targets, ThreadDescriptorSize() is only used by lsan
> >> +// to get the pointer to thread-specific data keys in the thread control block.
> >> +#if (SANITIZER_FREEBSD || SANITIZER_LINUX) && !SANITIZER_ANDROID
> >> // sizeof(struct pthread) from glibc.
> >> static atomic_uintptr_t thread_descriptor_size;
> >>
> >> @@ -294,9 +249,18 @@ uptr ThreadDescriptorSize() {
> >> val = FIRST_32_SECOND_64(1168, 2288);
> >> else if (minor <= 14)
> >> val = FIRST_32_SECOND_64(1168, 2304);
> >> - else
> >> + else if (minor < 32) // Unknown version
> >> val = FIRST_32_SECOND_64(1216, 2304);
> >> + else // minor == 32
> >> + val = FIRST_32_SECOND_64(1344, 2496);
> >> }
> >> +#elif defined(__s390__) || defined(__sparc__)
> >> + // The size of a prefix of TCB including pthread::{specific_1stblock,specific}
> >> + // suffices. Just return offsetof(struct pthread, specific_used), which hasn't
> >> + // changed since 2007-05. Technically this applies to i386/x86_64 as well but
> >> + // we call _dl_get_tls_static_info and need the precise size of struct
> >> + // pthread.
> >> + return FIRST_32_SECOND_64(524, 1552);
> >> #elif defined(__mips__)
> >> // TODO(sagarthakur): add more values as per different glibc versions.
> >> val = FIRST_32_SECOND_64(1152, 1776);
> >> @@ -320,21 +284,12 @@ uptr ThreadDescriptorSize() {
> >> val = 1776;
> >> #elif defined(__powerpc64__)
> >> val = 1776; // from glibc.ppc64le 2.20-8.fc21
> >> -#elif defined(__s390__)
> >> - val = FIRST_32_SECOND_64(1152, 1776); // valid for glibc 2.22
> >> #endif
> >> if (val)
> >> atomic_store_relaxed(&thread_descriptor_size, val);
> >> return val;
> >> }
> >>
> >> -// The offset at which pointer to self is located in the thread descriptor.
> >> -const uptr kThreadSelfOffset = FIRST_32_SECOND_64(8, 16);
> >> -
> >> -uptr ThreadSelfOffset() {
> >> - return kThreadSelfOffset;
> >> -}
> >> -
> >> #if defined(__mips__) || defined(__powerpc64__) || SANITIZER_RISCV64
> >> // TlsPreTcbSize includes size of struct pthread_descr and size of tcb
> >> // head structure. It lies before the static tls blocks.
> >> @@ -353,68 +308,74 @@ static uptr TlsPreTcbSize() {
> >> }
> >> #endif
> >>
> >> -uptr ThreadSelf() {
> >> - uptr descr_addr;
> >> -#if defined(__i386__)
> >> - asm("mov %%gs:%c1,%0" : "=r"(descr_addr) : "i"(kThreadSelfOffset));
> >> -#elif defined(__x86_64__)
> >> - asm("mov %%fs:%c1,%0" : "=r"(descr_addr) : "i"(kThreadSelfOffset));
> >> -#elif defined(__mips__)
> >> - // MIPS uses TLS variant I. The thread pointer (in hardware register $29)
> >> - // points to the end of the TCB + 0x7000. The pthread_descr structure is
> >> - // immediately in front of the TCB. TlsPreTcbSize() includes the size of the
> >> - // TCB and the size of pthread_descr.
> >> - const uptr kTlsTcbOffset = 0x7000;
> >> - uptr thread_pointer;
> >> - asm volatile(".set push;\
> >> - .set mips64r2;\
> >> - rdhwr %0,$29;\
> >> - .set pop" : "=r" (thread_pointer));
> >> - descr_addr = thread_pointer - kTlsTcbOffset - TlsPreTcbSize();
> >> -#elif defined(__aarch64__) || defined(__arm__)
> >> - descr_addr = reinterpret_cast<uptr>(__builtin_thread_pointer()) -
> >> - ThreadDescriptorSize();
> >> -#elif SANITIZER_RISCV64
> >> - // https://github.com/riscv/riscv-elf-psabi-doc/issues/53
> >> - uptr thread_pointer = reinterpret_cast<uptr>(__builtin_thread_pointer());
> >> - descr_addr = thread_pointer - TlsPreTcbSize();
> >> -#elif defined(__s390__)
> >> - descr_addr = reinterpret_cast<uptr>(__builtin_thread_pointer());
> >> -#elif defined(__powerpc64__)
> >> - // PPC64LE uses TLS variant I. The thread pointer (in GPR 13)
> >> - // points to the end of the TCB + 0x7000. The pthread_descr structure is
> >> - // immediately in front of the TCB. TlsPreTcbSize() includes the size of the
> >> - // TCB and the size of pthread_descr.
> >> - const uptr kTlsTcbOffset = 0x7000;
> >> - uptr thread_pointer;
> >> - asm("addi %0,13,%1" : "=r"(thread_pointer) : "I"(-kTlsTcbOffset));
> >> - descr_addr = thread_pointer - TlsPreTcbSize();
> >> -#else
> >> -#error "unsupported CPU arch"
> >> -#endif
> >> - return descr_addr;
> >> -}
> >> -#endif // (x86_64 || i386 || MIPS) && SANITIZER_LINUX
> >> +#if !SANITIZER_GO
> >> +namespace {
> >> +struct TlsBlock {
> >> + uptr begin, end, align;
> >> + size_t tls_modid;
> >> + bool operator<(const TlsBlock &rhs) const { return begin < rhs.begin; }
> >> +};
> >> +} // namespace
> >>
> >> -#if SANITIZER_FREEBSD
> >> -static void **ThreadSelfSegbase() {
> >> - void **segbase = 0;
> >> -#if defined(__i386__)
> >> - // sysarch(I386_GET_GSBASE, segbase);
> >> - __asm __volatile("mov %%gs:0, %0" : "=r" (segbase));
> >> -#elif defined(__x86_64__)
> >> - // sysarch(AMD64_GET_FSBASE, segbase);
> >> - __asm __volatile("movq %%fs:0, %0" : "=r" (segbase));
> >> -#else
> >> -#error "unsupported CPU arch"
> >> +extern "C" void *__tls_get_addr(size_t *);
> >> +
> >> +static int CollectStaticTlsBlocks(struct dl_phdr_info *info, size_t size,
> >> + void *data) {
> >> + if (!info->dlpi_tls_modid)
> >> + return 0;
> >> + uptr begin = (uptr)info->dlpi_tls_data;
> >> +#ifndef __s390__
> >> + if (!g_use_dlpi_tls_data) {
> >> + // Call __tls_get_addr as a fallback. This forces TLS allocation on glibc
> >> + // and FreeBSD.
> >> + size_t mod_and_off[2] = {info->dlpi_tls_modid, 0};
> >> + begin = (uptr)__tls_get_addr(mod_and_off);
> >> + }
> >> #endif
> >> - return segbase;
> >> + for (unsigned i = 0; i != info->dlpi_phnum; ++i)
> >> + if (info->dlpi_phdr[i].p_type == PT_TLS) {
> >> + static_cast<InternalMmapVector<TlsBlock> *>(data)->push_back(
> >> + TlsBlock{begin, begin + info->dlpi_phdr[i].p_memsz,
> >> + info->dlpi_phdr[i].p_align, info->dlpi_tls_modid});
> >> + break;
> >> + }
> >> + return 0;
> >> }
> >>
> >> -uptr ThreadSelf() {
> >> - return (uptr)ThreadSelfSegbase()[2];
> >> -}
> >> -#endif // SANITIZER_FREEBSD
> >> +__attribute__((unused)) static void GetStaticTlsBoundary(uptr *addr, uptr *size,
> >> + uptr *align) {
> >> + InternalMmapVector<TlsBlock> ranges;
> >> + dl_iterate_phdr(CollectStaticTlsBlocks, &ranges);
> >> + uptr len = ranges.size();
> >> + Sort(ranges.begin(), len);
> >> + // Find the range with tls_modid=1. For glibc, because libc.so uses PT_TLS,
> >> + // this module is guaranteed to exist and is one of the initially loaded
> >> + // modules.
> >> + uptr one = 0;
> >> + while (one != len && ranges[one].tls_modid != 1) ++one;
> >> + if (one == len) {
> >> + // This may happen with musl if no module uses PT_TLS.
> >> + *addr = 0;
> >> + *size = 0;
> >> + *align = 1;
> >> + return;
> >> + }
> >> + // Find the maximum consecutive ranges. We consider two modules consecutive if
> >> + // the gap is smaller than the alignment. The dynamic loader places static TLS
> >> + // blocks this way not to waste space.
> >> + uptr l = one;
> >> + *align = ranges[l].align;
> >> + while (l != 0 && ranges[l].begin < ranges[l - 1].end + ranges[l - 1].align)
> >> + *align = Max(*align, ranges[--l].align);
> >> + uptr r = one + 1;
> >> + while (r != len && ranges[r].begin < ranges[r - 1].end + ranges[r - 1].align)
> >> + *align = Max(*align, ranges[r++].align);
> >> + *addr = ranges[l].begin;
> >> + *size = ranges[r - 1].end - ranges[l].begin;
> >> +}
> >> +#endif // !SANITIZER_GO
> >> +#endif // (x86_64 || i386 || mips || ...) && (SANITIZER_FREEBSD ||
> >> + // SANITIZER_LINUX) && !SANITIZER_ANDROID
> >>
> >> #if SANITIZER_NETBSD
> >> static struct tls_tcb * ThreadSelfTlsTcb() {
> >> @@ -465,33 +426,67 @@ static void GetTls(uptr *addr, uptr *size) {
> >> *addr = 0;
> >> *size = 0;
> >> }
> >> -#elif SANITIZER_LINUX
> >> -#if defined(__x86_64__) || defined(__i386__) || defined(__s390__)
> >> - *addr = ThreadSelf();
> >> - *size = GetTlsSize();
> >> +#elif SANITIZER_GLIBC && defined(__x86_64__)
> >> + // For x86-64, use an O(1) approach which requires precise
> >> + // ThreadDescriptorSize. g_tls_size was initialized in InitTlsSize.
> >> + asm("mov %%fs:16,%0" : "=r"(*addr));
> >> + *size = g_tls_size;
> >> *addr -= *size;
> >> *addr += ThreadDescriptorSize();
> >> -#elif defined(__mips__) || defined(__aarch64__) || defined(__powerpc64__) || \
> >> - defined(__arm__) || SANITIZER_RISCV64
> >> - *addr = ThreadSelf();
> >> - *size = GetTlsSize();
> >> +#elif SANITIZER_GLIBC && defined(__powerpc64__)
> >> + // Workaround for glibc<2.25(?). 2.27 is known to not need this.
> >> + uptr tp;
> >> + asm("addi %0,13,-0x7000" : "=r"(tp));
> >> + const uptr pre_tcb_size = TlsPreTcbSize();
> >> + *addr = tp - pre_tcb_size;
> >> + *size = g_tls_size + pre_tcb_size;
> >> +#elif SANITIZER_FREEBSD || SANITIZER_LINUX
> >> + uptr align;
> >> + GetStaticTlsBoundary(addr, size, &align);
> >> +#if defined(__x86_64__) || defined(__i386__) || defined(__s390__) || \
> >> + defined(__sparc__)
> >> + if (SANITIZER_GLIBC) {
> >> +#if defined(__x86_64__) || defined(__i386__)
> >> + align = Max<uptr>(align, 64);
> >> #else
> >> - *addr = 0;
> >> - *size = 0;
> >> + align = Max<uptr>(align, 16);
> >> #endif
> >> -#elif SANITIZER_FREEBSD
> >> - void** segbase = ThreadSelfSegbase();
> >> - *addr = 0;
> >> - *size = 0;
> >> - if (segbase != 0) {
> >> - // tcbalign = 16
> >> - // tls_size = round(tls_static_space, tcbalign);
> >> - // dtv = segbase[1];
> >> - // dtv[2] = segbase - tls_static_space;
> >> - void **dtv = (void**) segbase[1];
> >> - *addr = (uptr) dtv[2];
> >> - *size = (*addr == 0) ? 0 : ((uptr) segbase[0] - (uptr) dtv[2]);
> >> }
> >> + const uptr tp = RoundUpTo(*addr + *size, align);
> >> +
> >> + // lsan requires the range to additionally cover the static TLS surplus
> >> + // (elf/dl-tls.c defines 1664). Otherwise there may be false positives for
> >> + // allocations only referenced by tls in dynamically loaded modules.
> >> + if (SANITIZER_GLIBC)
> >> + *size += 1644;
> >> + else if (SANITIZER_FREEBSD)
> >> + *size += 128; // RTLD_STATIC_TLS_EXTRA
> >> +
> >> + // Extend the range to include the thread control block. On glibc, lsan needs
> >> + // the range to include pthread::{specific_1stblock,specific} so that
> >> + // allocations only referenced by pthread_setspecific can be scanned. This may
> >> + // underestimate by at most TLS_TCB_ALIGN-1 bytes but it should be fine
> >> + // because the number of bytes after pthread::specific is larger.
> >> + *addr = tp - RoundUpTo(*size, align);
> >> + *size = tp - *addr + ThreadDescriptorSize();
> >> +#else
> >> + if (SANITIZER_GLIBC)
> >> + *size += 1664;
> >> + else if (SANITIZER_FREEBSD)
> >> + *size += 128; // RTLD_STATIC_TLS_EXTRA
> >> +#if defined(__mips__) || defined(__powerpc64__) || SANITIZER_RISCV64
> >> + const uptr pre_tcb_size = TlsPreTcbSize();
> >> + *addr -= pre_tcb_size;
> >> + *size += pre_tcb_size;
> >> +#else
> >> + // arm and aarch64 reserve two words at TP, so this underestimates the range.
> >> + // However, this is sufficient for the purpose of finding the pointers to
> >> + // thread-specific data keys.
> >> + const uptr tcb_size = ThreadDescriptorSize();
> >> + *addr -= tcb_size;
> >> + *size += tcb_size;
> >> +#endif
> >> +#endif
> >> #elif SANITIZER_NETBSD
> >> struct tls_tcb * const tcb = ThreadSelfTlsTcb();
> >> *addr = 0;
> >> @@ -518,15 +513,13 @@ static void GetTls(uptr *addr, uptr *size) {
> >>
> >> #if !SANITIZER_GO
> >> uptr GetTlsSize() {
> >> -#if SANITIZER_FREEBSD || SANITIZER_ANDROID || SANITIZER_NETBSD || \
> >> +#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \
> >> SANITIZER_SOLARIS
> >> uptr addr, size;
> >> GetTls(&addr, &size);
> >> return size;
> >> -#elif defined(__mips__) || defined(__powerpc64__) || SANITIZER_RISCV64
> >> - return RoundUpTo(g_tls_size + TlsPreTcbSize(), 16);
> >> #else
> >> - return g_tls_size;
> >> + return 0;
> >> #endif
> >> }
> >> #endif
> >> @@ -547,10 +540,9 @@ void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
> >> if (!main) {
> >> // If stack and tls intersect, make them non-intersecting.
> >> if (*tls_addr > *stk_addr && *tls_addr < *stk_addr + *stk_size) {
> >> - CHECK_GT(*tls_addr + *tls_size, *stk_addr);
> >> - CHECK_LE(*tls_addr + *tls_size, *stk_addr + *stk_size);
> >> - *stk_size -= *tls_size;
> >> - *tls_addr = *stk_addr + *stk_size;
> >> + if (*stk_addr + *stk_size < *tls_addr + *tls_size)
> >> + *tls_size = *stk_addr + *stk_size - *tls_addr;
> >> + *stk_size = *tls_addr - *stk_addr;
> >> }
> >> }
> >> #endif
> >> @@ -569,20 +561,12 @@ struct DlIteratePhdrData {
> >> bool first;
> >> };
> >>
> >> -static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) {
> >> - DlIteratePhdrData *data = (DlIteratePhdrData*)arg;
> >> - InternalScopedString module_name(kMaxPathLength);
> >> - if (data->first) {
> >> - data->first = false;
> >> - // First module is the binary itself.
> >> - ReadBinaryNameCached(module_name.data(), module_name.size());
> >> - } else if (info->dlpi_name) {
> >> - module_name.append("%s", info->dlpi_name);
> >> - }
> >> +static int AddModuleSegments(const char *module_name, dl_phdr_info *info,
> >> + InternalMmapVectorNoCtor<LoadedModule> *modules) {
> >> if (module_name[0] == '\0')
> >> return 0;
> >> LoadedModule cur_module;
> >> - cur_module.set(module_name.data(), info->dlpi_addr);
> >> + cur_module.set(module_name, info->dlpi_addr);
> >> for (int i = 0; i < (int)info->dlpi_phnum; i++) {
> >> const Elf_Phdr *phdr = &info->dlpi_phdr[i];
> >> if (phdr->p_type == PT_LOAD) {
> >> @@ -594,7 +578,26 @@ static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) {
> >> writable);
> >> }
> >> }
> >> - data->modules->push_back(cur_module);
> >> + modules->push_back(cur_module);
> >> + return 0;
> >> +}
> >> +
> >> +static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) {
> >> + DlIteratePhdrData *data = (DlIteratePhdrData *)arg;
> >> + if (data->first) {
> >> + InternalMmapVector<char> module_name(kMaxPathLength);
> >> + data->first = false;
> >> + // First module is the binary itself.
> >> + ReadBinaryNameCached(module_name.data(), module_name.size());
> >> + return AddModuleSegments(module_name.data(), info, data->modules);
> >> + }
> >> +
> >> + if (info->dlpi_name) {
> >> + InternalScopedString module_name;
> >> + module_name.append("%s", info->dlpi_name);
> >> + return AddModuleSegments(module_name.data(), info, data->modules);
> >> + }
> >> +
> >> return 0;
> >> }
> >>
> >> @@ -729,13 +732,9 @@ u32 GetNumberOfCPUs() {
> >> #elif SANITIZER_SOLARIS
> >> return sysconf(_SC_NPROCESSORS_ONLN);
> >> #else
> >> -#if defined(CPU_COUNT)
> >> cpu_set_t CPUs;
> >> CHECK_EQ(sched_getaffinity(0, sizeof(cpu_set_t), &CPUs), 0);
> >> return CPU_COUNT(&CPUs);
> >> -#else
> >> - return 1;
> >> -#endif
> >> #endif
> >> }
> >>
> >> @@ -802,20 +801,13 @@ void LogMessageOnPrintf(const char *str) {
> >>
> >> #endif // SANITIZER_LINUX
> >>
> >> -#if SANITIZER_LINUX && !SANITIZER_GO
> >> +#if SANITIZER_GLIBC && !SANITIZER_GO
> >> // glibc crashes when using clock_gettime from a preinit_array function as the
> >> // vDSO function pointers haven't been initialized yet. __progname is
> >> // initialized after the vDSO function pointers, so if it exists, is not null
> >> // and is not empty, we can use clock_gettime.
> >> extern "C" SANITIZER_WEAK_ATTRIBUTE char *__progname;
> >> -inline bool CanUseVDSO() {
> >> - // Bionic is safe, it checks for the vDSO function pointers to be initialized.
> >> - if (SANITIZER_ANDROID)
> >> - return true;
> >> - if (&__progname && __progname && *__progname)
> >> - return true;
> >> - return false;
> >> -}
> >> +inline bool CanUseVDSO() { return &__progname && __progname && *__progname; }
> >>
> >> // MonotonicNanoTime is a timing function that can leverage the vDSO by calling
> >> // clock_gettime. real_clock_gettime only exists if clock_gettime is
> >> @@ -835,13 +827,13 @@ u64 MonotonicNanoTime() {
> >> return (u64)ts.tv_sec * (1000ULL * 1000 * 1000) + ts.tv_nsec;
> >> }
> >> #else
> >> -// Non-Linux & Go always use the syscall.
> >> +// Non-glibc & Go always use the regular function.
> >> u64 MonotonicNanoTime() {
> >> timespec ts;
> >> - internal_clock_gettime(CLOCK_MONOTONIC, &ts);
> >> + clock_gettime(CLOCK_MONOTONIC, &ts);
> >> return (u64)ts.tv_sec * (1000ULL * 1000 * 1000) + ts.tv_nsec;
> >> }
> >> -#endif // SANITIZER_LINUX && !SANITIZER_GO
> >> +#endif // SANITIZER_GLIBC && !SANITIZER_GO
> >>
> >> void ReExec() {
> >> const char *pathname = "/proc/self/exe";
> >> @@ -910,6 +902,65 @@ uptr MapDynamicShadow(uptr shadow_size_bytes, uptr shadow_scale,
> >> return shadow_start;
> >> }
> >>
> >> +static uptr MmapSharedNoReserve(uptr addr, uptr size) {
> >> + return internal_mmap(
> >> + reinterpret_cast<void *>(addr), size, PROT_READ | PROT_WRITE,
> >> + MAP_FIXED | MAP_SHARED | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
> >> +}
> >> +
> >> +static uptr MremapCreateAlias(uptr base_addr, uptr alias_addr,
> >> + uptr alias_size) {
> >> +#if SANITIZER_LINUX
> >> + return internal_mremap(reinterpret_cast<void *>(base_addr), 0, alias_size,
> >> + MREMAP_MAYMOVE | MREMAP_FIXED,
> >> + reinterpret_cast<void *>(alias_addr));
> >> +#else
> >> + CHECK(false && "mremap is not supported outside of Linux");
> >> + return 0;
> >> +#endif
> >> +}
> >> +
> >> +static void CreateAliases(uptr start_addr, uptr alias_size, uptr num_aliases) {
> >> + uptr total_size = alias_size * num_aliases;
> >> + uptr mapped = MmapSharedNoReserve(start_addr, total_size);
> >> + CHECK_EQ(mapped, start_addr);
> >> +
> >> + for (uptr i = 1; i < num_aliases; ++i) {
> >> + uptr alias_addr = start_addr + i * alias_size;
> >> + CHECK_EQ(MremapCreateAlias(start_addr, alias_addr, alias_size), alias_addr);
> >> + }
> >> +}
> >> +
> >> +uptr MapDynamicShadowAndAliases(uptr shadow_size, uptr alias_size,
> >> + uptr num_aliases, uptr ring_buffer_size) {
> >> + CHECK_EQ(alias_size & (alias_size - 1), 0);
> >> + CHECK_EQ(num_aliases & (num_aliases - 1), 0);
> >> + CHECK_EQ(ring_buffer_size & (ring_buffer_size - 1), 0);
> >> +
> >> + const uptr granularity = GetMmapGranularity();
> >> + shadow_size = RoundUpTo(shadow_size, granularity);
> >> + CHECK_EQ(shadow_size & (shadow_size - 1), 0);
> >> +
> >> + const uptr alias_region_size = alias_size * num_aliases;
> >> + const uptr alignment =
> >> + 2 * Max(Max(shadow_size, alias_region_size), ring_buffer_size);
> >> + const uptr left_padding = ring_buffer_size;
> >> +
> >> + const uptr right_size = alignment;
> >> + const uptr map_size = left_padding + 2 * alignment;
> >> +
> >> + const uptr map_start = reinterpret_cast<uptr>(MmapNoAccess(map_size));
> >> + CHECK_NE(map_start, static_cast<uptr>(-1));
> >> + const uptr right_start = RoundUpTo(map_start + left_padding, alignment);
> >> +
> >> + UnmapFromTo(map_start, right_start - left_padding);
> >> + UnmapFromTo(right_start + right_size, map_start + map_size);
> >> +
> >> + CreateAliases(right_start + right_size / 2, alias_size, num_aliases);
> >> +
> >> + return right_start;
> >> +}
> >> +
> >> void InitializePlatformCommonFlags(CommonFlags *cf) {
> >> #if SANITIZER_ANDROID
> >> if (&__libc_get_static_tls_bounds == nullptr)
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_local_address_space_view.h b/libsanitizer/sanitizer_common/sanitizer_local_address_space_view.h
> >> index 5d1b5264b5e..0e19c4d4a80 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_local_address_space_view.h
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_local_address_space_view.h
> >> @@ -7,7 +7,7 @@
> >> //===----------------------------------------------------------------------===//
> >> //
> >> // `LocalAddressSpaceView` provides the local (i.e. target and current address
> >> -// space are the same) implementation of the `AddressSpaveView` interface which
> >> +// space are the same) implementation of the `AddressSpaceView` interface which
> >> // provides a simple interface to load memory from another process (i.e.
> >> // out-of-process)
> >> //
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_mac.cpp b/libsanitizer/sanitizer_common/sanitizer_mac.cpp
> >> index 011ec6f4a0b..f4c6b442a14 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_mac.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_mac.cpp
> >> @@ -37,13 +37,21 @@
> >> extern char **environ;
> >> #endif
> >>
> >> -#if defined(__has_include) && __has_include(<os/trace.h>) && defined(__BLOCKS__)
> >> +#if defined(__has_include) && __has_include(<os/trace.h>)
> >> #define SANITIZER_OS_TRACE 1
> >> #include <os/trace.h>
> >> #else
> >> #define SANITIZER_OS_TRACE 0
> >> #endif
> >>
> >> +// import new crash reporting api
> >> +#if defined(__has_include) && __has_include(<CrashReporterClient.h>)
> >> +#define HAVE_CRASHREPORTERCLIENT_H 1
> >> +#include <CrashReporterClient.h>
> >> +#else
> >> +#define HAVE_CRASHREPORTERCLIENT_H 0
> >> +#endif
> >> +
> >> #if !SANITIZER_IOS
> >> #include <crt_externs.h> // for _NSGetArgv and _NSGetEnviron
> >> #else
> >> @@ -62,6 +70,7 @@ extern "C" {
> >> #include <mach/mach_time.h>
> >> #include <mach/vm_statistics.h>
> >> #include <malloc/malloc.h>
> >> +#include <os/log.h>
> >> #include <pthread.h>
> >> #include <sched.h>
> >> #include <signal.h>
> >> @@ -133,6 +142,12 @@ uptr internal_munmap(void *addr, uptr length) {
> >> return munmap(addr, length);
> >> }
> >>
> >> +uptr internal_mremap(void *old_address, uptr old_size, uptr new_size, int flags,
> >> + void *new_address) {
> >> + CHECK(false && "internal_mremap is unimplemented on Mac");
> >> + return 0;
> >> +}
> >> +
> >> int internal_mprotect(void *addr, uptr length, int prot) {
> >> return mprotect(addr, length, prot);
> >> }
> >> @@ -444,7 +459,7 @@ uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {
> >> // On OS X the executable path is saved to the stack by dyld. Reading it
> >> // from there is much faster than calling dladdr, especially for large
> >> // binaries with symbols.
> >> - InternalScopedString exe_path(kMaxPathLength);
> >> + InternalMmapVector<char> exe_path(kMaxPathLength);
> >> uint32_t size = exe_path.size();
> >> if (_NSGetExecutablePath(exe_path.data(), &size) == 0 &&
> >> realpath(exe_path.data(), buf) != 0) {
> >> @@ -620,6 +635,23 @@ constexpr u16 GetOSMajorKernelOffset() {
> >>
> >> using VersStr = char[64];
> >>
> >> +static uptr ApproximateOSVersionViaKernelVersion(VersStr vers) {
> >> + u16 kernel_major = GetDarwinKernelVersion().major;
> >> + u16 offset = GetOSMajorKernelOffset();
> >> + CHECK_GE(kernel_major, offset);
> >> + u16 os_major = kernel_major - offset;
> >> +
> >> + const char *format = "%d.0";
> >> + if (TARGET_OS_OSX) {
> >> + if (os_major >= 16) { // macOS 11+
> >> + os_major -= 5;
> >> + } else { // macOS 10.15 and below
> >> + format = "10.%d";
> >> + }
> >> + }
> >> + return internal_snprintf(vers, sizeof(VersStr), format, os_major);
> >> +}
> >> +
> >> static void GetOSVersion(VersStr vers) {
> >> uptr len = sizeof(VersStr);
> >> if (SANITIZER_IOSSIM) {
> >> @@ -633,17 +665,19 @@ static void GetOSVersion(VersStr vers) {
> >> } else {
> >> int res =
> >> internal_sysctlbyname("kern.osproductversion", vers, &len, nullptr, 0);
> >> - if (res) {
> >> - // Fallback for XNU 17 (macOS 10.13) and below that do not provide the
> >> - // `kern.osproductversion` property.
> >> - u16 kernel_major = GetDarwinKernelVersion().major;
> >> - u16 offset = GetOSMajorKernelOffset();
> >> - CHECK_LE(kernel_major, 17);
> >> - CHECK_GE(kernel_major, offset);
> >> - u16 os_major = kernel_major - offset;
> >> -
> >> - auto format = TARGET_OS_OSX ? "10.%d" : "%d.0";
> >> - len = internal_snprintf(vers, len, format, os_major);
> >> +
> >> + // XNU 17 (macOS 10.13) and below do not provide the sysctl
> >> + // `kern.osproductversion` entry (res != 0).
> >> + bool no_os_version = res != 0;
> >> +
> >> + // For launchd, sanitizer initialization runs before sysctl is setup
> >> + // (res == 0 && len != strlen(vers), vers is not a valid version). However,
> >> + // the kernel version `kern.osrelease` is available.
> >> + bool launchd = (res == 0 && internal_strlen(vers) < 3);
> >> + if (launchd) CHECK_EQ(internal_getpid(), 1);
> >> +
> >> + if (no_os_version || launchd) {
> >> + len = ApproximateOSVersionViaKernelVersion(vers);
> >> }
> >> }
> >> CHECK_LT(len, sizeof(VersStr));
> >> @@ -681,7 +715,7 @@ static void MapToMacos(u16 *major, u16 *minor) {
> >> }
> >>
> >> static MacosVersion GetMacosAlignedVersionInternal() {
> >> - VersStr vers;
> >> + VersStr vers = {};
> >> GetOSVersion(vers);
> >>
> >> u16 major, minor;
> >> @@ -707,7 +741,7 @@ MacosVersion GetMacosAlignedVersion() {
> >> }
> >>
> >> DarwinKernelVersion GetDarwinKernelVersion() {
> >> - VersStr vers;
> >> + VersStr vers = {};
> >> uptr len = sizeof(VersStr);
> >> int res = internal_sysctlbyname("kern.osrelease", vers, &len, nullptr, 0);
> >> CHECK_EQ(res, 0);
> >> @@ -751,7 +785,51 @@ static BlockingMutex syslog_lock(LINKER_INITIALIZED);
> >> void WriteOneLineToSyslog(const char *s) {
> >> #if !SANITIZER_GO
> >> syslog_lock.CheckLocked();
> >> - asl_log(nullptr, nullptr, ASL_LEVEL_ERR, "%s", s);
> >> + if (GetMacosAlignedVersion() >= MacosVersion(10, 12)) {
> >> + os_log_error(OS_LOG_DEFAULT, "%{public}s", s);
> >> + } else {
> >> + asl_log(nullptr, nullptr, ASL_LEVEL_ERR, "%s", s);
> >> + }
> >> +#endif
> >> +}
> >> +
> >> +// buffer to store crash report application information
> >> +static char crashreporter_info_buff[__sanitizer::kErrorMessageBufferSize] = {};
> >> +static BlockingMutex crashreporter_info_mutex(LINKER_INITIALIZED);
> >> +
> >> +extern "C" {
> >> +// Integrate with crash reporter libraries.
> >> +#if HAVE_CRASHREPORTERCLIENT_H
> >> +CRASH_REPORTER_CLIENT_HIDDEN
> >> +struct crashreporter_annotations_t gCRAnnotations
> >> + __attribute__((section("__DATA," CRASHREPORTER_ANNOTATIONS_SECTION))) = {
> >> + CRASHREPORTER_ANNOTATIONS_VERSION,
> >> + 0,
> >> + 0,
> >> + 0,
> >> + 0,
> >> + 0,
> >> + 0,
> >> +#if CRASHREPORTER_ANNOTATIONS_VERSION > 4
> >> + 0,
> >> +#endif
> >> +};
> >> +
> >> +#else
> >> +// fall back to old crashreporter api
> >> +static const char *__crashreporter_info__ __attribute__((__used__)) =
> >> + &crashreporter_info_buff[0];
> >> +asm(".desc ___crashreporter_info__, 0x10");
> >> +#endif
> >> +
> >> +} // extern "C"
> >> +
> >> +static void CRAppendCrashLogMessage(const char *msg) {
> >> + BlockingMutexLock l(&crashreporter_info_mutex);
> >> + internal_strlcat(crashreporter_info_buff, msg,
> >> + sizeof(crashreporter_info_buff));
> >> +#if HAVE_CRASHREPORTERCLIENT_H
> >> + (void)CRSetCrashLogMessage(crashreporter_info_buff);
> >> #endif
> >> }
> >>
> >> @@ -947,7 +1025,7 @@ void MaybeReexec() {
> >> if (DyldNeedsEnvVariable() && !lib_is_in_env) {
> >> // DYLD_INSERT_LIBRARIES is not set or does not contain the runtime
> >> // library.
> >> - InternalScopedString program_name(1024);
> >> + InternalMmapVector<char> program_name(1024);
> >> uint32_t buf_size = program_name.size();
> >> _NSGetExecutablePath(program_name.data(), &buf_size);
> >> char *new_env = const_cast<char*>(info.dli_fname);
> >> @@ -1066,7 +1144,7 @@ char **GetArgv() {
> >> return *_NSGetArgv();
> >> }
> >>
> >> -#if SANITIZER_IOS
> >> +#if SANITIZER_IOS && !SANITIZER_IOSSIM
> >> // The task_vm_info struct is normally provided by the macOS SDK, but we need
> >> // fields only available in 10.12+. Declare the struct manually to be able to
> >> // build against older SDKs.
> >> @@ -1106,26 +1184,35 @@ static uptr GetTaskInfoMaxAddress() {
> >>
> >> uptr GetMaxUserVirtualAddress() {
> >> static uptr max_vm = GetTaskInfoMaxAddress();
> >> - if (max_vm != 0)
> >> - return max_vm - 1;
> >> + if (max_vm != 0) {
> >> + const uptr ret_value = max_vm - 1;
> >> + CHECK_LE(ret_value, SANITIZER_MMAP_RANGE_SIZE);
> >> + return ret_value;
> >> + }
> >>
> >> // xnu cannot provide vm address limit
> >> # if SANITIZER_WORDSIZE == 32
> >> - return 0xffe00000 - 1;
> >> + constexpr uptr fallback_max_vm = 0xffe00000 - 1;
> >> # else
> >> - return 0x200000000 - 1;
> >> + constexpr uptr fallback_max_vm = 0x200000000 - 1;
> >> # endif
> >> + static_assert(fallback_max_vm <= SANITIZER_MMAP_RANGE_SIZE,
> >> + "Max virtual address must be less than mmap range size.");
> >> + return fallback_max_vm;
> >> }
> >>
> >> #else // !SANITIZER_IOS
> >>
> >> uptr GetMaxUserVirtualAddress() {
> >> # if SANITIZER_WORDSIZE == 64
> >> - return (1ULL << 47) - 1; // 0x00007fffffffffffUL;
> >> + constexpr uptr max_vm = (1ULL << 47) - 1; // 0x00007fffffffffffUL;
> >> # else // SANITIZER_WORDSIZE == 32
> >> static_assert(SANITIZER_WORDSIZE == 32, "Wrong wordsize");
> >> - return (1ULL << 32) - 1; // 0xffffffff;
> >> + constexpr uptr max_vm = (1ULL << 32) - 1; // 0xffffffff;
> >> # endif
> >> + static_assert(max_vm <= SANITIZER_MMAP_RANGE_SIZE,
> >> + "Max virtual address must be less than mmap range size.");
> >> + return max_vm;
> >> }
> >> #endif
> >>
> >> @@ -1180,6 +1267,12 @@ uptr MapDynamicShadow(uptr shadow_size_bytes, uptr shadow_scale,
> >> return shadow_start;
> >> }
> >>
> >> +uptr MapDynamicShadowAndAliases(uptr shadow_size, uptr alias_size,
> >> + uptr num_aliases, uptr ring_buffer_size) {
> >> + CHECK(false && "HWASan aliasing is unimplemented on Mac");
> >> + return 0;
> >> +}
> >> +
> >> uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding,
> >> uptr *largest_gap_found,
> >> uptr *max_occupied_addr) {
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_mac.h b/libsanitizer/sanitizer_common/sanitizer_mac.h
> >> index a2c42b3bf4f..0b6af5a3c0e 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_mac.h
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_mac.h
> >> @@ -14,26 +14,6 @@
> >>
> >> #include "sanitizer_common.h"
> >> #include "sanitizer_platform.h"
> >> -
> >> -/* TARGET_OS_OSX is not present in SDKs before Darwin16 (macOS 10.12) use
> >> - TARGET_OS_MAC (we have no support for iOS in any form for these versions,
> >> - so there's no ambiguity). */
> >> -#if !defined(TARGET_OS_OSX) && TARGET_OS_MAC
> >> -# define TARGET_OS_OSX 1
> >> -#endif
> >> -
> >> -/* Other TARGET_OS_xxx are not present on earlier versions, define them to
> >> - 0 (we have no support for them; they are not valid targets anyway). */
> >> -#ifndef TARGET_OS_IOS
> >> -#define TARGET_OS_IOS 0
> >> -#endif
> >> -#ifndef TARGET_OS_TV
> >> -#define TARGET_OS_TV 0
> >> -#endif
> >> -#ifndef TARGET_OS_WATCH
> >> -#define TARGET_OS_WATCH 0
> >> -#endif
> >> -
> >> #if SANITIZER_MAC
> >> #include "sanitizer_posix.h"
> >>
> >> @@ -84,22 +64,5 @@ void RestrictMemoryToMaxAddress(uptr max_address);
> >>
> >> } // namespace __sanitizer
> >>
> >> -extern "C" {
> >> -static char __crashreporter_info_buff__[__sanitizer::kErrorMessageBufferSize] =
> >> - {};
> >> -static const char *__crashreporter_info__ __attribute__((__used__)) =
> >> - &__crashreporter_info_buff__[0];
> >> -asm(".desc ___crashreporter_info__, 0x10");
> >> -} // extern "C"
> >> -
> >> -namespace __sanitizer {
> >> -static BlockingMutex crashreporter_info_mutex(LINKER_INITIALIZED);
> >> -
> >> -inline void CRAppendCrashLogMessage(const char *msg) {
> >> - BlockingMutexLock l(&crashreporter_info_mutex);
> >> - internal_strlcat(__crashreporter_info_buff__, msg,
> >> - sizeof(__crashreporter_info_buff__)); }
> >> -} // namespace __sanitizer
> >> -
> >> #endif // SANITIZER_MAC
> >> #endif // SANITIZER_MAC_H
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_malloc_mac.inc b/libsanitizer/sanitizer_common/sanitizer_malloc_mac.inc
> >> index 647bcdfe105..e3b664f68b6 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_malloc_mac.inc
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_malloc_mac.inc
> >> @@ -120,11 +120,7 @@ INTERCEPTOR(int, malloc_make_nonpurgeable, void *ptr) {
> >>
> >> INTERCEPTOR(void, malloc_set_zone_name, malloc_zone_t *zone, const char *name) {
> >> COMMON_MALLOC_ENTER();
> >> - // Allocate |sizeof(COMMON_MALLOC_ZONE_NAME "-") + internal_strlen(name)|
> >> - // bytes.
> >> - size_t buflen =
> >> - sizeof(COMMON_MALLOC_ZONE_NAME "-") + (name ? internal_strlen(name) : 0);
> >> - InternalScopedString new_name(buflen);
> >> + InternalScopedString new_name;
> >> if (name && zone->introspect == sanitizer_zone.introspect) {
> >> new_name.append(COMMON_MALLOC_ZONE_NAME "-%s", name);
> >> name = new_name.data();
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_netbsd.cpp b/libsanitizer/sanitizer_common/sanitizer_netbsd.cpp
> >> index 98ac7365da0..ac20f915fef 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_netbsd.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_netbsd.cpp
> >> @@ -105,6 +105,12 @@ uptr internal_munmap(void *addr, uptr length) {
> >> return _REAL(munmap, addr, length);
> >> }
> >>
> >> +uptr internal_mremap(void *old_address, uptr old_size, uptr new_size, int flags,
> >> + void *new_address) {
> >> + CHECK(false && "internal_mremap is unimplemented on NetBSD");
> >> + return 0;
> >> +}
> >> +
> >> int internal_mprotect(void *addr, uptr length, int prot) {
> >> DEFINE__REAL(int, mprotect, void *a, uptr b, int c);
> >> return _REAL(mprotect, addr, length, prot);
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_platform.h b/libsanitizer/sanitizer_common/sanitizer_platform.h
> >> index b2372a025c0..2f6458431c8 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_platform.h
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_platform.h
> >> @@ -19,12 +19,25 @@
> >> # error "This operating system is not supported"
> >> #endif
> >>
> >> +// Get __GLIBC__ on a glibc platform. Exclude Android: features.h includes C
> >> +// function declarations into a .S file which doesn't compile.
> >> +// https://crbug.com/1162741
> >> +#if __has_include(<features.h>) && !defined(__ANDROID__)
> >> +#include <features.h>
> >> +#endif
> >> +
> >> #if defined(__linux__)
> >> # define SANITIZER_LINUX 1
> >> #else
> >> # define SANITIZER_LINUX 0
> >> #endif
> >>
> >> +#if defined(__GLIBC__)
> >> +# define SANITIZER_GLIBC 1
> >> +#else
> >> +# define SANITIZER_GLIBC 0
> >> +#endif
> >> +
> >> #if defined(__FreeBSD__)
> >> # define SANITIZER_FREEBSD 1
> >> #else
> >> @@ -46,6 +59,11 @@
> >> #if defined(__APPLE__)
> >> # define SANITIZER_MAC 1
> >> # include <TargetConditionals.h>
> >> +# if TARGET_OS_OSX
> >> +# define SANITIZER_OSX 1
> >> +# else
> >> +# define SANITIZER_OSX 0
> >> +# endif
> >> # if TARGET_OS_IPHONE
> >> # define SANITIZER_IOS 1
> >> # else
> >> @@ -60,6 +78,7 @@
> >> # define SANITIZER_MAC 0
> >> # define SANITIZER_IOS 0
> >> # define SANITIZER_IOSSIM 0
> >> +# define SANITIZER_OSX 0
> >> #endif
> >>
> >> #if defined(__APPLE__) && TARGET_OS_IPHONE && TARGET_OS_WATCH
> >> @@ -247,8 +266,12 @@
> >> #define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 38)
> >> #elif defined(__aarch64__)
> >> # if SANITIZER_MAC
> >> -// Darwin iOS/ARM64 has a 36-bit VMA, 64GiB VM
> >> -# define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 36)
> >> +# if SANITIZER_OSX || SANITIZER_IOSSIM
> >> +# define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 47)
> >> +# else
> >> + // Darwin iOS/ARM64 has a 36-bit VMA, 64GiB VM
> >> +# define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 36)
> >> +# endif
> >> # else
> >> # define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 48)
> >> # endif
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h b/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h
> >> index 18bab346ce6..731df710df5 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h
> >> @@ -46,6 +46,12 @@
> >> #define SI_LINUX_NOT_ANDROID 0
> >> #endif
> >>
> >> +#if SANITIZER_GLIBC
> >> +#define SI_GLIBC 1
> >> +#else
> >> +#define SI_GLIBC 0
> >> +#endif
> >> +
> >> #if SANITIZER_ANDROID
> >> #define SI_ANDROID 1
> >> #else
> >> @@ -159,7 +165,7 @@
> >> SANITIZER_INTERCEPT_MEMCMP && \
> >> ((SI_POSIX && _GNU_SOURCE) || SI_NETBSD || SI_FREEBSD)
> >> #define SANITIZER_INTERCEPT_STRNDUP SI_POSIX
> >> -#define SANITIZER_INTERCEPT___STRNDUP SI_LINUX_NOT_FREEBSD
> >> +#define SANITIZER_INTERCEPT___STRNDUP SI_GLIBC
> >> #if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \
> >> __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070
> >> #define SI_MAC_DEPLOYMENT_BELOW_10_7 1
> >> @@ -183,8 +189,8 @@
> >> #define SANITIZER_INTERCEPT_FPUTS SI_POSIX
> >> #define SANITIZER_INTERCEPT_PUTS SI_POSIX
> >>
> >> -#define SANITIZER_INTERCEPT_PREAD64 SI_LINUX_NOT_ANDROID || SI_SOLARIS32
> >> -#define SANITIZER_INTERCEPT_PWRITE64 SI_LINUX_NOT_ANDROID || SI_SOLARIS32
> >> +#define SANITIZER_INTERCEPT_PREAD64 (SI_GLIBC || SI_SOLARIS32)
> >> +#define SANITIZER_INTERCEPT_PWRITE64 (SI_GLIBC || SI_SOLARIS32)
> >>
> >> #define SANITIZER_INTERCEPT_READV SI_POSIX
> >> #define SANITIZER_INTERCEPT_WRITEV SI_POSIX
> >> @@ -192,8 +198,8 @@
> >> #define SANITIZER_INTERCEPT_PREADV \
> >> (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID)
> >> #define SANITIZER_INTERCEPT_PWRITEV SI_LINUX_NOT_ANDROID
> >> -#define SANITIZER_INTERCEPT_PREADV64 SI_LINUX_NOT_ANDROID
> >> -#define SANITIZER_INTERCEPT_PWRITEV64 SI_LINUX_NOT_ANDROID
> >> +#define SANITIZER_INTERCEPT_PREADV64 SI_GLIBC
> >> +#define SANITIZER_INTERCEPT_PWRITEV64 SI_GLIBC
> >>
> >> #define SANITIZER_INTERCEPT_PRCTL SI_LINUX
> >>
> >> @@ -201,16 +207,16 @@
> >> #define SANITIZER_INTERCEPT_STRPTIME SI_POSIX
> >>
> >> #define SANITIZER_INTERCEPT_SCANF SI_POSIX
> >> -#define SANITIZER_INTERCEPT_ISOC99_SCANF SI_LINUX_NOT_ANDROID
> >> +#define SANITIZER_INTERCEPT_ISOC99_SCANF SI_GLIBC
> >>
> >> #ifndef SANITIZER_INTERCEPT_PRINTF
> >> #define SANITIZER_INTERCEPT_PRINTF SI_POSIX
> >> #define SANITIZER_INTERCEPT_PRINTF_L (SI_FREEBSD || SI_NETBSD)
> >> -#define SANITIZER_INTERCEPT_ISOC99_PRINTF SI_LINUX_NOT_ANDROID
> >> +#define SANITIZER_INTERCEPT_ISOC99_PRINTF SI_GLIBC
> >> #endif
> >>
> >> #define SANITIZER_INTERCEPT___PRINTF_CHK \
> >> - (SANITIZER_INTERCEPT_PRINTF && SI_LINUX_NOT_ANDROID)
> >> + (SANITIZER_INTERCEPT_PRINTF && SI_GLIBC)
> >>
> >> #define SANITIZER_INTERCEPT_FREXP SI_NOT_FUCHSIA
> >> #define SANITIZER_INTERCEPT_FREXPF_FREXPL SI_POSIX
> >> @@ -220,13 +226,11 @@
> >> (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
> >> #define SANITIZER_INTERCEPT_GETPWENT \
> >> (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
> >> -#define SANITIZER_INTERCEPT_FGETGRENT_R \
> >> - (SI_FREEBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
> >> +#define SANITIZER_INTERCEPT_FGETGRENT_R (SI_GLIBC || SI_SOLARIS)
> >> #define SANITIZER_INTERCEPT_FGETPWENT SI_LINUX_NOT_ANDROID || SI_SOLARIS
> >> #define SANITIZER_INTERCEPT_GETPWENT_R \
> >> - (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
> >> -#define SANITIZER_INTERCEPT_FGETPWENT_R \
> >> - (SI_FREEBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
> >> + (SI_FREEBSD || SI_NETBSD || SI_GLIBC || SI_SOLARIS)
> >> +#define SANITIZER_INTERCEPT_FGETPWENT_R (SI_FREEBSD || SI_GLIBC || SI_SOLARIS)
> >> #define SANITIZER_INTERCEPT_SETPWENT \
> >> (SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
> >> #define SANITIZER_INTERCEPT_CLOCK_GETTIME \
> >> @@ -234,8 +238,8 @@
> >> #define SANITIZER_INTERCEPT_CLOCK_GETCPUCLOCKID SI_LINUX
> >> #define SANITIZER_INTERCEPT_GETITIMER SI_POSIX
> >> #define SANITIZER_INTERCEPT_TIME SI_POSIX
> >> -#define SANITIZER_INTERCEPT_GLOB SI_LINUX_NOT_ANDROID || SI_SOLARIS
> >> -#define SANITIZER_INTERCEPT_GLOB64 SI_LINUX_NOT_ANDROID
> >> +#define SANITIZER_INTERCEPT_GLOB (SI_GLIBC || SI_SOLARIS)
> >> +#define SANITIZER_INTERCEPT_GLOB64 SI_GLIBC
> >> #define SANITIZER_INTERCEPT_WAIT SI_POSIX
> >> #define SANITIZER_INTERCEPT_INET SI_POSIX
> >> #define SANITIZER_INTERCEPT_PTHREAD_GETSCHEDPARAM SI_POSIX
> >> @@ -250,8 +254,7 @@
> >> (SI_FREEBSD || SI_LINUX_NOT_ANDROID)
> >> #define SANITIZER_INTERCEPT_GETHOSTBYADDR_R \
> >> (SI_FREEBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
> >> -#define SANITIZER_INTERCEPT_GETHOSTENT_R \
> >> - (SI_FREEBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
> >> +#define SANITIZER_INTERCEPT_GETHOSTENT_R (SI_FREEBSD || SI_GLIBC || SI_SOLARIS)
> >> #define SANITIZER_INTERCEPT_GETSOCKOPT SI_POSIX
> >> #define SANITIZER_INTERCEPT_ACCEPT SI_POSIX
> >> #define SANITIZER_INTERCEPT_ACCEPT4 (SI_LINUX_NOT_ANDROID || SI_NETBSD)
> >> @@ -296,8 +299,7 @@
> >> (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
> >> #define SANITIZER_INTERCEPT_TCGETATTR SI_LINUX_NOT_ANDROID || SI_SOLARIS
> >> #define SANITIZER_INTERCEPT_REALPATH SI_POSIX
> >> -#define SANITIZER_INTERCEPT_CANONICALIZE_FILE_NAME \
> >> - (SI_LINUX_NOT_ANDROID || SI_SOLARIS)
> >> +#define SANITIZER_INTERCEPT_CANONICALIZE_FILE_NAME (SI_GLIBC || SI_SOLARIS)
> >> #define SANITIZER_INTERCEPT_CONFSTR \
> >> (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
> >> #define SANITIZER_INTERCEPT_SCHED_GETAFFINITY SI_LINUX_NOT_ANDROID
> >> @@ -324,7 +326,7 @@
> >> #define SANITIZER_INTERCEPT_SIGPROCMASK SI_POSIX
> >> #define SANITIZER_INTERCEPT_PTHREAD_SIGMASK SI_POSIX
> >> #define SANITIZER_INTERCEPT_BACKTRACE \
> >> - (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
> >> + (SI_FREEBSD || SI_NETBSD || SI_GLIBC || SI_SOLARIS)
> >> #define SANITIZER_INTERCEPT_GETMNTENT SI_LINUX
> >> #define SANITIZER_INTERCEPT_GETMNTENT_R SI_LINUX_NOT_ANDROID
> >> #define SANITIZER_INTERCEPT_STATFS \
> >> @@ -342,11 +344,11 @@
> >> #define SANITIZER_INTERCEPT_SHMCTL \
> >> (((SI_FREEBSD || SI_LINUX_NOT_ANDROID) && SANITIZER_WORDSIZE == 64) || \
> >> SI_NETBSD || SI_SOLARIS) // NOLINT
> >> -#define SANITIZER_INTERCEPT_RANDOM_R SI_LINUX_NOT_ANDROID
> >> +#define SANITIZER_INTERCEPT_RANDOM_R SI_GLIBC
> >> #define SANITIZER_INTERCEPT_PTHREAD_ATTR_GET SI_POSIX
> >> #define SANITIZER_INTERCEPT_PTHREAD_ATTR_GETINHERITSCHED \
> >> (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
> >> -#define SANITIZER_INTERCEPT_PTHREAD_ATTR_GETAFFINITY_NP SI_LINUX_NOT_ANDROID
> >> +#define SANITIZER_INTERCEPT_PTHREAD_ATTR_GETAFFINITY_NP SI_GLIBC
> >> #define SANITIZER_INTERCEPT_PTHREAD_ATTR_GET_SCHED SI_POSIX
> >> #define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPSHARED \
> >> (SI_POSIX && !SI_NETBSD)
> >> @@ -360,7 +362,7 @@
> >> #define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETROBUST_NP SI_LINUX_NOT_ANDROID
> >> #define SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GETPSHARED \
> >> (SI_POSIX && !SI_NETBSD)
> >> -#define SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GETKIND_NP SI_LINUX_NOT_ANDROID
> >> +#define SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GETKIND_NP SI_GLIBC
> >> #define SANITIZER_INTERCEPT_PTHREAD_CONDATTR_GETPSHARED (SI_POSIX && !SI_NETBSD)
> >> #define SANITIZER_INTERCEPT_PTHREAD_CONDATTR_GETCLOCK \
> >> (SI_LINUX_NOT_ANDROID || SI_SOLARIS)
> >> @@ -368,7 +370,7 @@
> >> (SI_LINUX_NOT_ANDROID && !SI_NETBSD)
> >> #define SANITIZER_INTERCEPT_THR_EXIT SI_FREEBSD
> >> #define SANITIZER_INTERCEPT_TMPNAM SI_POSIX
> >> -#define SANITIZER_INTERCEPT_TMPNAM_R SI_LINUX_NOT_ANDROID || SI_SOLARIS
> >> +#define SANITIZER_INTERCEPT_TMPNAM_R (SI_GLIBC || SI_SOLARIS)
> >> #define SANITIZER_INTERCEPT_PTSNAME SI_LINUX
> >> #define SANITIZER_INTERCEPT_PTSNAME_R SI_LINUX
> >> #define SANITIZER_INTERCEPT_TTYNAME SI_POSIX
> >> @@ -381,7 +383,7 @@
> >> #define SANITIZER_INTERCEPT_LGAMMAL (SI_POSIX && !SI_NETBSD)
> >> #define SANITIZER_INTERCEPT_LGAMMA_R (SI_FREEBSD || SI_LINUX || SI_SOLARIS)
> >> #define SANITIZER_INTERCEPT_LGAMMAL_R SI_LINUX_NOT_ANDROID || SI_SOLARIS
> >> -#define SANITIZER_INTERCEPT_DRAND48_R SI_LINUX_NOT_ANDROID
> >> +#define SANITIZER_INTERCEPT_DRAND48_R SI_GLIBC
> >> #define SANITIZER_INTERCEPT_RAND_R \
> >> (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
> >> #define SANITIZER_INTERCEPT_ICONV \
> >> @@ -396,12 +398,12 @@
> >> (SI_LINUX || SI_FREEBSD || SI_NETBSD || SI_MAC || SI_SOLARIS)
> >>
> >> #define SANITIZER_INTERCEPT_PTHREAD_MUTEX SI_POSIX
> >> -#define SANITIZER_INTERCEPT___PTHREAD_MUTEX SI_LINUX_NOT_ANDROID
> >> +#define SANITIZER_INTERCEPT___PTHREAD_MUTEX SI_GLIBC
> >> #define SANITIZER_INTERCEPT___LIBC_MUTEX SI_NETBSD
> >> #define SANITIZER_INTERCEPT_PTHREAD_SETNAME_NP \
> >> - (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
> >> + (SI_FREEBSD || SI_NETBSD || SI_GLIBC || SI_SOLARIS)
> >> #define SANITIZER_INTERCEPT_PTHREAD_GETNAME_NP \
> >> - (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
> >> + (SI_FREEBSD || SI_NETBSD || SI_GLIBC || SI_SOLARIS)
> >>
> >> #define SANITIZER_INTERCEPT_TLS_GET_ADDR \
> >> (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
> >> @@ -419,19 +421,19 @@
> >> #else
> >> #define SANITIZER_INTERCEPT_AEABI_MEM 0
> >> #endif
> >> -#define SANITIZER_INTERCEPT___BZERO SI_MAC || SI_LINUX_NOT_ANDROID
> >> +#define SANITIZER_INTERCEPT___BZERO SI_MAC || SI_GLIBC
> >> #define SANITIZER_INTERCEPT_BZERO SI_LINUX_NOT_ANDROID
> >> #define SANITIZER_INTERCEPT_FTIME (!SI_FREEBSD && !SI_NETBSD && SI_POSIX)
> >> -#define SANITIZER_INTERCEPT_XDR SI_LINUX_NOT_ANDROID || SI_SOLARIS
> >> -#define SANITIZER_INTERCEPT_XDRREC SI_LINUX_NOT_ANDROID
> >> +#define SANITIZER_INTERCEPT_XDR (SI_GLIBC || SI_SOLARIS)
> >> +#define SANITIZER_INTERCEPT_XDRREC SI_GLIBC
> >> #define SANITIZER_INTERCEPT_TSEARCH \
> >> (SI_LINUX_NOT_ANDROID || SI_MAC || SI_NETBSD || SI_SOLARIS)
> >> -#define SANITIZER_INTERCEPT_LIBIO_INTERNALS SI_LINUX_NOT_ANDROID
> >> +#define SANITIZER_INTERCEPT_LIBIO_INTERNALS SI_GLIBC
> >> #define SANITIZER_INTERCEPT_FOPEN SI_POSIX
> >> -#define SANITIZER_INTERCEPT_FOPEN64 SI_LINUX_NOT_ANDROID || SI_SOLARIS32
> >> +#define SANITIZER_INTERCEPT_FOPEN64 (SI_GLIBC || SI_SOLARIS32)
> >> #define SANITIZER_INTERCEPT_OPEN_MEMSTREAM \
> >> (SI_LINUX_NOT_ANDROID || SI_NETBSD || SI_SOLARIS)
> >> -#define SANITIZER_INTERCEPT_OBSTACK SI_LINUX_NOT_ANDROID
> >> +#define SANITIZER_INTERCEPT_OBSTACK SI_GLIBC
> >> #define SANITIZER_INTERCEPT_FFLUSH SI_POSIX
> >> #define SANITIZER_INTERCEPT_FCLOSE SI_POSIX
> >>
> >> @@ -456,7 +458,7 @@
> >> #define SANITIZER_INTERCEPT_CTERMID_R (SI_MAC || SI_FREEBSD || SI_SOLARIS)
> >>
> >> #define SANITIZER_INTERCEPTOR_HOOKS \
> >> - (SI_LINUX || SI_MAC || SI_WINDOWS || SI_NETBSD)
> >> + (SI_LINUX || SI_MAC || SI_WINDOWS || SI_FREEBSD || SI_NETBSD || SI_SOLARIS)
> >> #define SANITIZER_INTERCEPT_RECV_RECVFROM SI_POSIX
> >> #define SANITIZER_INTERCEPT_SEND_SENDTO SI_POSIX
> >> #define SANITIZER_INTERCEPT_EVENTFD_READ_WRITE SI_LINUX
> >> @@ -479,20 +481,12 @@
> >>
> >> #define SANITIZER_INTERCEPT_MMAP SI_POSIX
> >> #define SANITIZER_INTERCEPT_MMAP64 SI_LINUX_NOT_ANDROID
> >> -#define SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO \
> >> - (!SI_FREEBSD && !SI_MAC && !SI_NETBSD && SI_NOT_FUCHSIA && SI_NOT_RTEMS && \
> >> - !SI_SOLARIS) // NOLINT
> >> +#define SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO (SI_GLIBC || SI_ANDROID)
> >> #define SANITIZER_INTERCEPT_MEMALIGN \
> >> (!SI_FREEBSD && !SI_MAC && !SI_NETBSD && SI_NOT_RTEMS)
> >> -#define SANITIZER_INTERCEPT___LIBC_MEMALIGN \
> >> - (!SI_FREEBSD && !SI_MAC && !SI_NETBSD && !SI_OPENBSD && SI_NOT_RTEMS && \
> >> - !SI_ANDROID) // NOLINT
> >> -#define SANITIZER_INTERCEPT_PVALLOC \
> >> - (!SI_FREEBSD && !SI_MAC && !SI_NETBSD && SI_NOT_FUCHSIA && SI_NOT_RTEMS && \
> >> - !SI_SOLARIS) // NOLINT
> >> -#define SANITIZER_INTERCEPT_CFREE \
> >> - (!SI_FREEBSD && !SI_MAC && !SI_NETBSD && SI_NOT_FUCHSIA && SI_NOT_RTEMS && \
> >> - !SI_SOLARIS && !SANITIZER_ANDROID) // NOLINT
> >> +#define SANITIZER_INTERCEPT___LIBC_MEMALIGN SI_GLIBC
> >> +#define SANITIZER_INTERCEPT_PVALLOC (SI_GLIBC || SI_ANDROID)
> >> +#define SANITIZER_INTERCEPT_CFREE (SI_GLIBC && !SANITIZER_RISCV64)
> >> #define SANITIZER_INTERCEPT_REALLOCARRAY SI_POSIX
> >> #define SANITIZER_INTERCEPT_ALIGNED_ALLOC (!SI_MAC && SI_NOT_RTEMS)
> >> #define SANITIZER_INTERCEPT_MALLOC_USABLE_SIZE (!SI_MAC && !SI_NETBSD)
> >> @@ -532,7 +526,7 @@
> >> #define SANITIZER_INTERCEPT_STRMODE (SI_NETBSD || SI_FREEBSD)
> >> #define SANITIZER_INTERCEPT_TTYENT SI_NETBSD
> >> #define SANITIZER_INTERCEPT_PROTOENT (SI_NETBSD || SI_LINUX)
> >> -#define SANITIZER_INTERCEPT_PROTOENT_R (SI_LINUX_NOT_ANDROID)
> >> +#define SANITIZER_INTERCEPT_PROTOENT_R SI_GLIBC
> >> #define SANITIZER_INTERCEPT_NETENT SI_NETBSD
> >> #define SANITIZER_INTERCEPT_SETVBUF \
> >> (SI_NETBSD || SI_FREEBSD || SI_LINUX || SI_MAC)
> >> @@ -583,7 +577,7 @@
> >> #define SANITIZER_INTERCEPT_GETENTROPY SI_FREEBSD
> >> #define SANITIZER_INTERCEPT_QSORT \
> >> (SI_POSIX && !SI_IOSSIM && !SI_WATCHOS && !SI_TVOS && !SI_ANDROID)
> >> -#define SANITIZER_INTERCEPT_QSORT_R (SI_LINUX && !SI_ANDROID)
> >> +#define SANITIZER_INTERCEPT_QSORT_R SI_GLIBC
> >> // sigaltstack on i386 macOS cannot be intercepted due to setjmp()
> >> // calling it and assuming that it does not clobber registers.
> >> #define SANITIZER_INTERCEPT_SIGALTSTACK \
> >> @@ -591,4 +585,25 @@
> >> #define SANITIZER_INTERCEPT_UNAME (SI_POSIX && !SI_FREEBSD)
> >> #define SANITIZER_INTERCEPT___XUNAME SI_FREEBSD
> >>
> >> +// This macro gives a way for downstream users to override the above
> >> +// interceptor macros irrespective of the platform they are on. They have
> >> +// to do two things:
> >> +// 1. Build compiler-rt with -DSANITIZER_OVERRIDE_INTERCEPTORS.
> >> +// 2. Provide a header file named sanitizer_intercept_overriders.h in the
> >> +// include path for their compiler-rt build.
> >> +// An example of an overrider for strlen interceptor that one can list in
> >> +// sanitizer_intercept_overriders.h is as follows:
> >> +//
> >> +// #ifdef SANITIZER_INTERCEPT_STRLEN
> >> +// #undef SANITIZER_INTERCEPT_STRLEN
> >> +// #define SANITIZER_INTERCEPT_STRLEN <value of choice>
> >> +// #endif
> >> +//
> >> +// This "feature" is useful for downstream users who do not want some of
> >> +// their libc funtions to be intercepted. They can selectively disable
> >> +// interception of those functions.
> >> +#ifdef SANITIZER_OVERRIDE_INTERCEPTORS
> >> +#include <sanitizer_intercept_overriders.h>
> >> +#endif
> >> +
> >> #endif // #ifndef SANITIZER_PLATFORM_INTERCEPTORS_H
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.cpp b/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.cpp
> >> index b1c15be58de..b5a45ae72cd 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.cpp
> >> @@ -35,7 +35,10 @@
> >> #include <sys/stat.h>
> >> #include <sys/statvfs.h>
> >> #include <sys/time.h>
> >> +#pragma clang diagnostic push
> >> +#pragma clang diagnostic ignored "-W#warnings"
> >> #include <sys/timeb.h>
> >> +#pragma clang diagnostic pop
> >> #include <sys/times.h>
> >> #include <sys/timespec.h>
> >> #include <sys/types.h>
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cpp b/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cpp
> >> index f22f5039128..c51327e1269 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cpp
> >> @@ -26,12 +26,9 @@
> >>
> >> // 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. Beware that with <sys/stat.h>, struct stat
> >> -// takes the form of struct stat64 on 32-bit platforms if _FILE_OFFSET_BITS=64.
> >> -// Also, for some platforms (e.g. mips) there are additional members in the
> >> -// <sys/stat.h> struct stat:s.
> >> +// fine with newer headers, too.
> >> #include <linux/posix_types.h>
> >> -#if defined(__x86_64__)
> >> +#if defined(__x86_64__) || defined(__mips__)
> >> #include <sys/stat.h>
> >> #else
> >> #define ino_t __kernel_ino_t
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp
> >> index 1427cec48c4..35a690cba5c 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp
> >> @@ -11,18 +11,19 @@
> >> // Sizes and layouts of platform-specific POSIX data structures.
> >> //===----------------------------------------------------------------------===//
> >>
> >> -#include "sanitizer_platform.h"
> >> -
> >> -#if SANITIZER_LINUX || SANITIZER_MAC
> >> +#if defined(__linux__) || defined(__APPLE__)
> >> // Tests in this file assume that off_t-dependent data structures match the
> >> // libc ABI. For example, struct dirent here is what readdir() function (as
> >> // exported from libc) returns, and not the user-facing "dirent", which
> >> // depends on _FILE_OFFSET_BITS setting.
> >> // To get this "true" dirent definition, we undefine _FILE_OFFSET_BITS below.
> >> -#ifdef _FILE_OFFSET_BITS
> >> #undef _FILE_OFFSET_BITS
> >> #endif
> >>
> >> +// Must go after undef _FILE_OFFSET_BITS.
> >> +#include "sanitizer_platform.h"
> >> +
> >> +#if SANITIZER_LINUX || SANITIZER_MAC
> >> // Must go after undef _FILE_OFFSET_BITS.
> >> #include "sanitizer_glibc_version.h"
> >>
> >> @@ -37,6 +38,7 @@
> >> #include <pwd.h>
> >> #include <signal.h>
> >> #include <stddef.h>
> >> +#include <stdio.h>
> >> #include <sys/mman.h>
> >> #include <sys/resource.h>
> >> #include <sys/socket.h>
> >> @@ -58,7 +60,6 @@
> >> #endif
> >>
> >> #if !SANITIZER_ANDROID
> >> -#include <fstab.h>
> >> #include <sys/mount.h>
> >> #include <sys/timeb.h>
> >> #include <utmpx.h>
> >> @@ -110,20 +111,31 @@ typedef struct user_fpregs elf_fpregset_t;
> >> #include <wordexp.h>
> >> #endif
> >>
> >> -#if SANITIZER_LINUX && !SANITIZER_ANDROID
> >> -#include <glob.h>
> >> -#include <obstack.h>
> >> -#include <mqueue.h>
> >> +#if SANITIZER_LINUX
> >> +#if SANITIZER_GLIBC
> >> +#include <fstab.h>
> >> #include <net/if_ppp.h>
> >> #include <netax25/ax25.h>
> >> #include <netipx/ipx.h>
> >> #include <netrom/netrom.h>
> >> +#include <obstack.h>
> >> #if HAVE_RPC_XDR_H
> >> # include <rpc/xdr.h>
> >> #endif
> >> #include <scsi/scsi.h>
> >> -#include <sys/mtio.h>
> >> +#else
> >> +#include <linux/if_ppp.h>
> >> +#include <linux/kd.h>
> >> +#include <linux/ppp_defs.h>
> >> +#endif // SANITIZER_GLIBC
> >> +
> >> +#if SANITIZER_ANDROID
> >> +#include <linux/mtio.h>
> >> +#else
> >> +#include <glob.h>
> >> +#include <mqueue.h>
> >> #include <sys/kd.h>
> >> +#include <sys/mtio.h>
> >> #include <sys/shm.h>
> >> #include <sys/statvfs.h>
> >> #include <sys/timex.h>
> >> @@ -142,20 +154,14 @@ typedef struct user_fpregs elf_fpregset_t;
> >> #include <sys/msg.h>
> >> #include <sys/ipc.h>
> >> #include <crypt.h>
> >> -#endif // SANITIZER_LINUX && !SANITIZER_ANDROID
> >> +#endif // SANITIZER_ANDROID
> >>
> >> -#if SANITIZER_ANDROID
> >> -#include <linux/kd.h>
> >> -#include <linux/mtio.h>
> >> -#include <linux/ppp_defs.h>
> >> -#include <linux/if_ppp.h>
> >> -#endif
> >> -
> >> -#if SANITIZER_LINUX
> >> #include <link.h>
> >> #include <sys/vfs.h>
> >> #include <sys/epoll.h>
> >> #include <linux/capability.h>
> >> +#else
> >> +#include <fstab.h>
> >> #endif // SANITIZER_LINUX
> >>
> >> #if SANITIZER_MAC
> >> @@ -202,8 +208,11 @@ namespace __sanitizer {
> >> unsigned struct_statfs64_sz = sizeof(struct statfs64);
> >> #endif // (SANITIZER_MAC && !TARGET_CPU_ARM64) && !SANITIZER_IOS
> >>
> >> -#if !SANITIZER_ANDROID
> >> +#if SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_MAC
> >> unsigned struct_fstab_sz = sizeof(struct fstab);
> >> +#endif // SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD ||
> >> + // SANITIZER_MAC
> >> +#if !SANITIZER_ANDROID
> >> unsigned struct_statfs_sz = sizeof(struct statfs);
> >> unsigned struct_sockaddr_sz = sizeof(struct sockaddr);
> >> unsigned ucontext_t_sz = sizeof(ucontext_t);
> >> @@ -299,7 +308,7 @@ unsigned struct_ElfW_Phdr_sz = sizeof(ElfW(Phdr));
> >> unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
> >> #endif
> >>
> >> -#if SANITIZER_LINUX && !SANITIZER_ANDROID
> >> +#if SANITIZER_GLIBC
> >> int glob_nomatch = GLOB_NOMATCH;
> >> int glob_altdirfunc = GLOB_ALTDIRFUNC;
> >> #endif
> >> @@ -422,7 +431,9 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
> >> unsigned struct_input_id_sz = sizeof(struct input_id);
> >> unsigned struct_mtpos_sz = sizeof(struct mtpos);
> >> unsigned struct_rtentry_sz = sizeof(struct rtentry);
> >> +#if SANITIZER_GLIBC || SANITIZER_ANDROID
> >> unsigned struct_termio_sz = sizeof(struct termio);
> >> +#endif
> >> unsigned struct_vt_consize_sz = sizeof(struct vt_consize);
> >> unsigned struct_vt_sizes_sz = sizeof(struct vt_sizes);
> >> unsigned struct_vt_stat_sz = sizeof(struct vt_stat);
> >> @@ -447,7 +458,7 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
> >> unsigned struct_vt_mode_sz = sizeof(struct vt_mode);
> >> #endif // SANITIZER_LINUX
> >>
> >> -#if SANITIZER_LINUX && !SANITIZER_ANDROID
> >> +#if SANITIZER_GLIBC
> >> unsigned struct_ax25_parms_struct_sz = sizeof(struct ax25_parms_struct);
> >> unsigned struct_cyclades_monitor_sz = sizeof(struct cyclades_monitor);
> >> #if EV_VERSION > (0x010000)
> >> @@ -470,12 +481,10 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
> >> unsigned struct_sockaddr_ax25_sz = sizeof(struct sockaddr_ax25);
> >> unsigned struct_unimapdesc_sz = sizeof(struct unimapdesc);
> >> unsigned struct_unimapinit_sz = sizeof(struct unimapinit);
> >> -#endif // SANITIZER_LINUX && !SANITIZER_ANDROID
> >>
> >> -#if SANITIZER_LINUX && !SANITIZER_ANDROID
> >> unsigned struct_audio_buf_info_sz = sizeof(struct audio_buf_info);
> >> unsigned struct_ppp_stats_sz = sizeof(struct ppp_stats);
> >> -#endif // (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
> >> +#endif // SANITIZER_GLIBC
> >>
> >> #if !SANITIZER_ANDROID && !SANITIZER_MAC
> >> unsigned struct_sioc_sg_req_sz = sizeof(struct sioc_sg_req);
> >> @@ -881,6 +890,7 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
> >> unsigned IOCTL_PIO_UNIMAP = PIO_UNIMAP;
> >> unsigned IOCTL_PIO_UNIMAPCLR = PIO_UNIMAPCLR;
> >> unsigned IOCTL_PIO_UNISCRNMAP = PIO_UNISCRNMAP;
> >> +#if SANITIZER_GLIBC
> >> unsigned IOCTL_SCSI_IOCTL_GET_IDLUN = SCSI_IOCTL_GET_IDLUN;
> >> unsigned IOCTL_SCSI_IOCTL_PROBE_HOST = SCSI_IOCTL_PROBE_HOST;
> >> unsigned IOCTL_SCSI_IOCTL_TAGGED_DISABLE = SCSI_IOCTL_TAGGED_DISABLE;
> >> @@ -899,6 +909,7 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
> >> unsigned IOCTL_SIOCNRGETPARMS = SIOCNRGETPARMS;
> >> unsigned IOCTL_SIOCNRRTCTL = SIOCNRRTCTL;
> >> unsigned IOCTL_SIOCNRSETPARMS = SIOCNRSETPARMS;
> >> +#endif
> >> unsigned IOCTL_TIOCGSERIAL = TIOCGSERIAL;
> >> unsigned IOCTL_TIOCSERGETMULTI = TIOCSERGETMULTI;
> >> unsigned IOCTL_TIOCSERSETMULTI = TIOCSERSETMULTI;
> >> @@ -969,7 +980,7 @@ CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phdr);
> >> CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phnum);
> >> #endif // SANITIZER_LINUX || SANITIZER_FREEBSD
> >>
> >> -#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
> >> +#if SANITIZER_GLIBC || SANITIZER_FREEBSD
> >> CHECK_TYPE_SIZE(glob_t);
> >> CHECK_SIZE_AND_OFFSET(glob_t, gl_pathc);
> >> CHECK_SIZE_AND_OFFSET(glob_t, gl_pathv);
> >> @@ -980,7 +991,7 @@ CHECK_SIZE_AND_OFFSET(glob_t, gl_readdir);
> >> CHECK_SIZE_AND_OFFSET(glob_t, gl_opendir);
> >> CHECK_SIZE_AND_OFFSET(glob_t, gl_lstat);
> >> CHECK_SIZE_AND_OFFSET(glob_t, gl_stat);
> >> -#endif
> >> +#endif // SANITIZER_GLIBC || SANITIZER_FREEBSD
> >>
> >> CHECK_TYPE_SIZE(addrinfo);
> >> CHECK_SIZE_AND_OFFSET(addrinfo, ai_flags);
> >> @@ -1003,17 +1014,27 @@ CHECK_TYPE_SIZE(iovec);
> >> CHECK_SIZE_AND_OFFSET(iovec, iov_base);
> >> CHECK_SIZE_AND_OFFSET(iovec, iov_len);
> >>
> >> +// In POSIX, int msg_iovlen; socklen_t msg_controllen; socklen_t cmsg_len; but
> >> +// many implementations don't conform to the standard. Since we pick the
> >> +// non-conforming glibc definition, exclude the checks for musl (incompatible
> >> +// sizes but compatible offsets).
> >> CHECK_TYPE_SIZE(msghdr);
> >> CHECK_SIZE_AND_OFFSET(msghdr, msg_name);
> >> CHECK_SIZE_AND_OFFSET(msghdr, msg_namelen);
> >> CHECK_SIZE_AND_OFFSET(msghdr, msg_iov);
> >> +#if SANITIZER_GLIBC || SANITIZER_ANDROID
> >> CHECK_SIZE_AND_OFFSET(msghdr, msg_iovlen);
> >> +#endif
> >> CHECK_SIZE_AND_OFFSET(msghdr, msg_control);
> >> +#if SANITIZER_GLIBC || SANITIZER_ANDROID
> >> CHECK_SIZE_AND_OFFSET(msghdr, msg_controllen);
> >> +#endif
> >> CHECK_SIZE_AND_OFFSET(msghdr, msg_flags);
> >>
> >> CHECK_TYPE_SIZE(cmsghdr);
> >> +#if SANITIZER_GLIBC || SANITIZER_ANDROID
> >> CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_len);
> >> +#endif
> >> CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_level);
> >> CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_type);
> >>
> >> @@ -1121,7 +1142,7 @@ CHECK_SIZE_AND_OFFSET(mntent, mnt_passno);
> >>
> >> CHECK_TYPE_SIZE(ether_addr);
> >>
> >> -#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
> >> +#if SANITIZER_GLIBC || SANITIZER_FREEBSD
> >> CHECK_TYPE_SIZE(ipc_perm);
> >> # if SANITIZER_FREEBSD
> >> CHECK_SIZE_AND_OFFSET(ipc_perm, key);
> >> @@ -1183,7 +1204,7 @@ CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_dstaddr);
> >> CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_data);
> >> #endif
> >>
> >> -#if SANITIZER_LINUX
> >> +#if SANITIZER_GLIBC || SANITIZER_ANDROID
> >> COMPILER_CHECK(sizeof(__sanitizer_struct_mallinfo) == sizeof(struct mallinfo));
> >> #endif
> >>
> >> @@ -1233,7 +1254,7 @@ COMPILER_CHECK(__sanitizer_XDR_DECODE == XDR_DECODE);
> >> COMPILER_CHECK(__sanitizer_XDR_FREE == XDR_FREE);
> >> #endif
> >>
> >> -#if SANITIZER_LINUX && !SANITIZER_ANDROID
> >> +#if SANITIZER_GLIBC
> >> COMPILER_CHECK(sizeof(__sanitizer_FILE) <= sizeof(FILE));
> >> CHECK_SIZE_AND_OFFSET(FILE, _flags);
> >> CHECK_SIZE_AND_OFFSET(FILE, _IO_read_ptr);
> >> @@ -1250,9 +1271,7 @@ CHECK_SIZE_AND_OFFSET(FILE, _IO_save_end);
> >> CHECK_SIZE_AND_OFFSET(FILE, _markers);
> >> CHECK_SIZE_AND_OFFSET(FILE, _chain);
> >> CHECK_SIZE_AND_OFFSET(FILE, _fileno);
> >> -#endif
> >>
> >> -#if SANITIZER_LINUX && !SANITIZER_ANDROID
> >> COMPILER_CHECK(sizeof(__sanitizer__obstack_chunk) <= sizeof(_obstack_chunk));
> >> CHECK_SIZE_AND_OFFSET(_obstack_chunk, limit);
> >> CHECK_SIZE_AND_OFFSET(_obstack_chunk, prev);
> >> @@ -1267,7 +1286,7 @@ CHECK_SIZE_AND_OFFSET(cookie_io_functions_t, read);
> >> CHECK_SIZE_AND_OFFSET(cookie_io_functions_t, write);
> >> CHECK_SIZE_AND_OFFSET(cookie_io_functions_t, seek);
> >> CHECK_SIZE_AND_OFFSET(cookie_io_functions_t, close);
> >> -#endif
> >> +#endif // SANITIZER_GLIBC
> >>
> >> #if SANITIZER_LINUX || SANITIZER_FREEBSD
> >> CHECK_TYPE_SIZE(sem_t);
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h
> >> index 0812039b038..836b178c131 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h
> >> @@ -83,7 +83,7 @@ const unsigned struct_kernel_stat64_sz = 104;
> >> #elif defined(__mips__)
> >> const unsigned struct_kernel_stat_sz = SANITIZER_ANDROID
> >> ? FIRST_32_SECOND_64(104, 128)
> >> - : FIRST_32_SECOND_64(144, 216);
> >> + : FIRST_32_SECOND_64(160, 216);
> >> const unsigned struct_kernel_stat64_sz = 104;
> >> #elif defined(__s390__) && !defined(__s390x__)
> >> const unsigned struct_kernel_stat_sz = 64;
> >> @@ -443,6 +443,8 @@ struct __sanitizer_cmsghdr {
> >> int cmsg_type;
> >> };
> >> #else
> >> +// In POSIX, int msg_iovlen; socklen_t msg_controllen; socklen_t cmsg_len; but
> >> +// many implementations don't conform to the standard.
> >> struct __sanitizer_msghdr {
> >> void *msg_name;
> >> unsigned msg_namelen;
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_posix.cpp b/libsanitizer/sanitizer_common/sanitizer_posix.cpp
> >> index 2e080098283..f8457a6aac4 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_posix.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_posix.cpp
> >> @@ -275,8 +275,8 @@ void ReportFile::Write(const char *buffer, uptr length) {
> >>
> >> bool GetCodeRangeForFile(const char *module, uptr *start, uptr *end) {
> >> MemoryMappingLayout proc_maps(/*cache_enabled*/false);
> >> - InternalScopedString buff(kMaxPathLength);
> >> - MemoryMappedSegment segment(buff.data(), kMaxPathLength);
> >> + InternalMmapVector<char> buff(kMaxPathLength);
> >> + MemoryMappedSegment segment(buff.data(), buff.size());
> >> while (proc_maps.Next(&segment)) {
> >> if (segment.IsExecutable() &&
> >> internal_strcmp(module, segment.filename) == 0) {
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_posix.h b/libsanitizer/sanitizer_common/sanitizer_posix.h
> >> index e1a2b48e5cd..b65dae64476 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_posix.h
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_posix.h
> >> @@ -40,6 +40,10 @@ uptr internal_write(fd_t fd, const void *buf, uptr count);
> >> uptr internal_mmap(void *addr, uptr length, int prot, int flags,
> >> int fd, u64 offset);
> >> uptr internal_munmap(void *addr, uptr length);
> >> +#if SANITIZER_LINUX
> >> +uptr internal_mremap(void *old_address, uptr old_size, uptr new_size, int flags,
> >> + void *new_address);
> >> +#endif
> >> int internal_mprotect(void *addr, uptr length, int prot);
> >> int internal_madvise(uptr addr, uptr length, int advice);
> >>
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp
> >> index 7ff48c35851..d1d8e509c4d 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp
> >> @@ -143,7 +143,7 @@ void Abort() {
> >> if (GetHandleSignalMode(SIGABRT) != kHandleSignalNo) {
> >> struct sigaction sigact;
> >> internal_memset(&sigact, 0, sizeof(sigact));
> >> - sigact.sa_sigaction = (sa_sigaction_t)SIG_DFL;
> >> + sigact.sa_handler = SIG_DFL;
> >> internal_sigaction(SIGABRT, &sigact, nullptr);
> >> }
> >> #endif
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_printf.cpp b/libsanitizer/sanitizer_common/sanitizer_printf.cpp
> >> index a032787114b..5d16dfde678 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_printf.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_printf.cpp
> >> @@ -249,26 +249,21 @@ static void NOINLINE SharedPrintfCodeNoBuffer(bool append_pid,
> >> va_list args) {
> >> va_list args2;
> >> va_copy(args2, args);
> >> - const int kLen = 16 * 1024;
> >> - int needed_length;
> >> + InternalMmapVector<char> v;
> >> + int needed_length = 0;
> >> char *buffer = local_buffer;
> >> // First try to print a message using a local buffer, and then fall back to
> >> // mmaped buffer.
> >> - for (int use_mmap = 0; use_mmap < 2; use_mmap++) {
> >> + for (int use_mmap = 0;; use_mmap++) {
> >> if (use_mmap) {
> >> va_end(args);
> >> va_copy(args, args2);
> >> - buffer = (char*)MmapOrDie(kLen, "Report");
> >> - buffer_size = kLen;
> >> + v.resize(needed_length + 1);
> >> + buffer_size = v.capacity();
> >> + v.resize(buffer_size);
> >> + buffer = &v[0];
> >> }
> >> needed_length = 0;
> >> - // Check that data fits into the current buffer.
> >> -# define CHECK_NEEDED_LENGTH \
> >> - if (needed_length >= buffer_size) { \
> >> - if (!use_mmap) continue; \
> >> - RAW_CHECK_MSG(needed_length < kLen, \
> >> - "Buffer in Report is too short!\n"); \
> >> - }
> >> // Fuchsia's logging infrastructure always keeps track of the logging
> >> // process, thread, and timestamp, so never prepend such information.
> >> if (!SANITIZER_FUCHSIA && append_pid) {
> >> @@ -277,18 +272,20 @@ static void NOINLINE SharedPrintfCodeNoBuffer(bool append_pid,
> >> if (common_flags()->log_exe_name && exe_name) {
> >> needed_length += internal_snprintf(buffer, buffer_size,
> >> "==%s", exe_name);
> >> - CHECK_NEEDED_LENGTH
> >> + if (needed_length >= buffer_size)
> >> + continue;
> >> }
> >> needed_length += internal_snprintf(
> >> buffer + needed_length, buffer_size - needed_length, "==%d==", pid);
> >> - CHECK_NEEDED_LENGTH
> >> + if (needed_length >= buffer_size)
> >> + continue;
> >> }
> >> needed_length += VSNPrintf(buffer + needed_length,
> >> buffer_size - needed_length, format, args);
> >> - CHECK_NEEDED_LENGTH
> >> + if (needed_length >= buffer_size)
> >> + continue;
> >> // If the message fit into the buffer, print it and exit.
> >> break;
> >> -# undef CHECK_NEEDED_LENGTH
> >> }
> >> RawWrite(buffer);
> >>
> >> @@ -297,9 +294,6 @@ static void NOINLINE SharedPrintfCodeNoBuffer(bool append_pid,
> >> CallPrintfAndReportCallback(buffer);
> >> LogMessageOnPrintf(buffer);
> >>
> >> - // If we had mapped any memory, clean up.
> >> - if (buffer != local_buffer)
> >> - UnmapOrDie((void *)buffer, buffer_size);
> >> va_end(args2);
> >> }
> >>
> >> @@ -346,13 +340,24 @@ int internal_snprintf(char *buffer, uptr length, const char *format, ...) {
> >>
> >> FORMAT(2, 3)
> >> 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_);
> >> - CHECK_LT(length_, size());
> >> + uptr prev_len = length();
> >> +
> >> + while (true) {
> >> + buffer_.resize(buffer_.capacity());
> >> +
> >> + va_list args;
> >> + va_start(args, format);
> >> + uptr sz = VSNPrintf(buffer_.data() + prev_len, buffer_.size() - prev_len,
> >> + format, args);
> >> + va_end(args);
> >> + if (sz < buffer_.size() - prev_len) {
> >> + buffer_.resize(prev_len + sz + 1);
> >> + break;
> >> + }
> >> +
> >> + buffer_.reserve(buffer_.capacity() * 2);
> >> + }
> >> + CHECK_EQ(buffer_[length()], '\0');
> >> }
> >>
> >> } // namespace __sanitizer
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_procmaps_common.cpp b/libsanitizer/sanitizer_common/sanitizer_procmaps_common.cpp
> >> index f2cfcffaf47..1b7dd46d8de 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_procmaps_common.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_procmaps_common.cpp
> >> @@ -120,7 +120,7 @@ void MemoryMappingLayout::LoadFromCache() {
> >> void MemoryMappingLayout::DumpListOfModules(
> >> InternalMmapVectorNoCtor<LoadedModule> *modules) {
> >> Reset();
> >> - InternalScopedString module_name(kMaxPathLength);
> >> + InternalMmapVector<char> module_name(kMaxPathLength);
> >> MemoryMappedSegment segment(module_name.data(), module_name.size());
> >> for (uptr i = 0; Next(&segment); i++) {
> >> const char *cur_name = segment.filename;
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_procmaps_mac.cpp b/libsanitizer/sanitizer_common/sanitizer_procmaps_mac.cpp
> >> index d02afcfe87a..1f53e3e46d8 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_procmaps_mac.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_procmaps_mac.cpp
> >> @@ -354,8 +354,8 @@ bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) {
> >> void MemoryMappingLayout::DumpListOfModules(
> >> InternalMmapVectorNoCtor<LoadedModule> *modules) {
> >> Reset();
> >> - InternalScopedString module_name(kMaxPathLength);
> >> - MemoryMappedSegment segment(module_name.data(), kMaxPathLength);
> >> + InternalMmapVector<char> module_name(kMaxPathLength);
> >> + MemoryMappedSegment segment(module_name.data(), module_name.size());
> >> MemoryMappedSegmentData data;
> >> segment.data_ = &data;
> >> while (Next(&segment)) {
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_procmaps_solaris.cpp b/libsanitizer/sanitizer_common/sanitizer_procmaps_solaris.cpp
> >> index 4063ec8deaa..bf813f235bb 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_procmaps_solaris.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_procmaps_solaris.cpp
> >> @@ -9,13 +9,13 @@
> >> // Information about the process mappings (Solaris-specific parts).
> >> //===----------------------------------------------------------------------===//
> >>
> >> +// Before Solaris 11.4, <procfs.h> doesn't work in a largefile environment.
> >> +#undef _FILE_OFFSET_BITS
> >> #include "sanitizer_platform.h"
> >> #if SANITIZER_SOLARIS
> >> #include "sanitizer_common.h"
> >> #include "sanitizer_procmaps.h"
> >>
> >> -// Before Solaris 11.4, <procfs.h> doesn't work in a largefile environment.
> >> -#undef _FILE_OFFSET_BITS
> >> #include <procfs.h>
> >> #include <limits.h>
> >>
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_ptrauth.h b/libsanitizer/sanitizer_common/sanitizer_ptrauth.h
> >> index a288068bf94..52003546948 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_ptrauth.h
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_ptrauth.h
> >> @@ -11,6 +11,24 @@
> >>
> >> #if __has_feature(ptrauth_calls)
> >> #include <ptrauth.h>
> >> +#elif defined(__ARM_FEATURE_PAC_DEFAULT) && !defined(__APPLE__)
> >> +inline unsigned long ptrauth_strip(void* __value, unsigned int __key) {
> >> + // On the stack the link register is protected with Pointer
> >> + // Authentication Code when compiled with -mbranch-protection.
> >> + // Let's stripping the PAC unconditionally because xpaclri is in
> >> + // the NOP space so will do nothing when it is not enabled or not available.
> >> + unsigned long ret;
> >> + asm volatile(
> >> + "mov x30, %1\n\t"
> >> + "hint #7\n\t" // xpaclri
> >> + "mov %0, x30\n\t"
> >> + : "=r"(ret)
> >> + : "r"(__value)
> >> + : "x30");
> >> + return ret;
> >> +}
> >> +#define ptrauth_auth_data(__value, __old_key, __old_data) __value
> >> +#define ptrauth_string_discriminator(__string) ((int)0)
> >> #else
> >> // Copied from <ptrauth.h>
> >> #define ptrauth_strip(__value, __key) __value
> >> @@ -18,6 +36,6 @@
> >> #define ptrauth_string_discriminator(__string) ((int)0)
> >> #endif
> >>
> >> -#define STRIP_PC(pc) ((uptr)ptrauth_strip(pc, 0))
> >> +#define STRIP_PAC_PC(pc) ((uptr)ptrauth_strip(pc, 0))
> >>
> >> #endif // SANITIZER_PTRAUTH_H
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_stackdepot.cpp b/libsanitizer/sanitizer_common/sanitizer_stackdepot.cpp
> >> index 4692f50d323..44a95214e38 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_stackdepot.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_stackdepot.cpp
> >> @@ -145,8 +145,7 @@ StackTrace StackDepotReverseMap::Get(u32 id) {
> >> if (!map_.size())
> >> return StackTrace();
> >> IdDescPair pair = {id, nullptr};
> >> - uptr idx =
> >> - InternalLowerBound(map_, 0, map_.size(), pair, IdDescPair::IdComparator);
> >> + uptr idx = InternalLowerBound(map_, pair, IdDescPair::IdComparator);
> >> if (idx > map_.size() || map_[idx].id != id)
> >> return StackTrace();
> >> return map_[idx].desc->load();
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp b/libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp
> >> index b28fc1cf736..07e4409f4a5 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp
> >> @@ -15,6 +15,7 @@
> >> #include "sanitizer_common.h"
> >> #include "sanitizer_flags.h"
> >> #include "sanitizer_platform.h"
> >> +#include "sanitizer_ptrauth.h"
> >>
> >> namespace __sanitizer {
> >>
> >> @@ -84,8 +85,8 @@ static inline uhwptr *GetCanonicFrame(uptr bp,
> >> // Nope, this does not look right either. This means the frame after next does
> >> // not have a valid frame pointer, but we can still extract the caller PC.
> >> // Unfortunately, there is no way to decide between GCC and LLVM frame
> >> - // layouts. Assume GCC.
> >> - return bp_prev - 1;
> >> + // layouts. Assume LLVM.
> >> + return bp_prev;
> >> #else
> >> return (uhwptr*)bp;
> >> #endif
> >> @@ -108,28 +109,21 @@ void BufferedStackTrace::UnwindFast(uptr pc, uptr bp, uptr stack_top,
> >> IsAligned((uptr)frame, sizeof(*frame)) &&
> >> size < max_depth) {
> >> #ifdef __powerpc__
> >> - // PowerPC ABIs specify that the return address is saved on the
> >> - // *caller's* stack frame. Thus we must dereference the back chain
> >> - // to find the caller frame before extracting it.
> >> + // PowerPC ABIs specify that the return address is saved at offset
> >> + // 16 of the *caller's* stack frame. Thus we must dereference the
> >> + // back chain to find the caller frame before extracting it.
> >> uhwptr *caller_frame = (uhwptr*)frame[0];
> >> if (!IsValidFrame((uptr)caller_frame, stack_top, bottom) ||
> >> !IsAligned((uptr)caller_frame, sizeof(uhwptr)))
> >> break;
> >> - // For most ABIs the offset where the return address is saved is two
> >> - // register sizes. The exception is the SVR4 ABI, which uses an
> >> - // offset of only one register size.
> >> -#ifdef _CALL_SYSV
> >> - uhwptr pc1 = caller_frame[1];
> >> -#else
> >> uhwptr pc1 = caller_frame[2];
> >> -#endif
> >> #elif defined(__s390__)
> >> uhwptr pc1 = frame[14];
> >> #elif defined(__riscv)
> >> // frame[-1] contains the return address
> >> uhwptr pc1 = frame[-1];
> >> #else
> >> - uhwptr pc1 = frame[1];
> >> + uhwptr pc1 = STRIP_PAC_PC((void *)frame[1]);
> >> #endif
> >> // Let's assume that any pointer in the 0th page (i.e. <0x1000 on i386 and
> >> // x86_64) is invalid and stop unwinding here. If we're adding support for
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace.h b/libsanitizer/sanitizer_common/sanitizer_stacktrace.h
> >> index 0350fe84b04..15616f899d0 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_stacktrace.h
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace.h
> >> @@ -67,8 +67,6 @@ struct StackTrace {
> >> static uptr GetCurrentPc();
> >> static inline uptr GetPreviousInstructionPc(uptr pc);
> >> static uptr GetNextInstructionPc(uptr pc);
> >> - typedef bool (*SymbolizeCallback)(const void *pc, char *out_buffer,
> >> - int out_size);
> >> };
> >>
> >> // Performance-critical, must be in the header.
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_stacktrace_libcdep.cpp
> >> index 7808ba9b0f5..738633209f0 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_stacktrace_libcdep.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace_libcdep.cpp
> >> @@ -23,8 +23,8 @@ void StackTrace::Print() const {
> >> Printf(" <empty stack>\n\n");
> >> return;
> >> }
> >> - InternalScopedString frame_desc(GetPageSizeCached() * 2);
> >> - InternalScopedString dedup_token(GetPageSizeCached());
> >> + InternalScopedString frame_desc;
> >> + InternalScopedString dedup_token;
> >> int dedup_frames = common_flags()->dedup_token_length;
> >> bool symbolize = RenderNeedsSymbolization(common_flags()->stack_trace_format);
> >> uptr frame_num = 0;
> >> @@ -125,7 +125,7 @@ void __sanitizer_symbolize_pc(uptr pc, const char *fmt, char *out_buf,
> >> out_buf[out_buf_size - 1] = 0;
> >> return;
> >> }
> >> - InternalScopedString frame_desc(GetPageSizeCached());
> >> + InternalScopedString frame_desc;
> >> uptr frame_num = 0;
> >> // Reserve one byte for the final 0.
> >> char *out_end = out_buf + out_buf_size - 1;
> >> @@ -156,7 +156,7 @@ void __sanitizer_symbolize_global(uptr data_addr, const char *fmt,
> >> out_buf[0] = 0;
> >> DataInfo DI;
> >> if (!Symbolizer::GetOrInit()->SymbolizeData(data_addr, &DI)) return;
> >> - InternalScopedString data_desc(GetPageSizeCached());
> >> + InternalScopedString data_desc;
> >> RenderData(&data_desc, fmt, &DI, common_flags()->strip_path_prefix);
> >> internal_strncpy(out_buf, data_desc.data(), out_buf_size);
> >> out_buf[out_buf_size - 1] = 0;
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp
> >> index 0f1cadfeae3..53cfddcfbe0 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp
> >> @@ -490,6 +490,9 @@ typedef user_regs_struct regs_struct;
> >> #ifndef NT_X86_XSTATE
> >> #define NT_X86_XSTATE 0x202
> >> #endif
> >> +#ifndef PTRACE_GETREGSET
> >> +#define PTRACE_GETREGSET 0x4204
> >> +#endif
> >> // Compiler may use FP registers to store pointers.
> >> static constexpr uptr kExtraRegs[] = {NT_X86_XSTATE, NT_FPREGSET};
> >>
> >> @@ -513,6 +516,8 @@ static constexpr uptr kExtraRegs[] = {0};
> >>
> >> #elif SANITIZER_RISCV64
> >> typedef struct user_regs_struct regs_struct;
> >> +// sys/ucontext.h already defines REG_SP as 2. Undefine it first.
> >> +#undef REG_SP
> >> #define REG_SP sp
> >> static constexpr uptr kExtraRegs[] = {0};
> >> #define ARCH_IOVEC_FOR_GETREGSET
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_suppressions.cpp b/libsanitizer/sanitizer_common/sanitizer_suppressions.cpp
> >> index 44c83a66c5f..a674034b8e2 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_suppressions.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_suppressions.cpp
> >> @@ -34,7 +34,7 @@ SuppressionContext::SuppressionContext(const char *suppression_types[],
> >> static bool GetPathAssumingFileIsRelativeToExec(const char *file_path,
> >> /*out*/char *new_file_path,
> >> uptr new_file_path_size) {
> >> - InternalScopedString exec(kMaxPathLength);
> >> + InternalMmapVector<char> exec(kMaxPathLength);
> >> if (ReadBinaryNameCached(exec.data(), exec.size())) {
> >> const char *file_name_pos = StripModuleName(exec.data());
> >> uptr path_to_exec_len = file_name_pos - exec.data();
> >> @@ -69,7 +69,7 @@ void SuppressionContext::ParseFromFile(const char *filename) {
> >> if (filename[0] == '\0')
> >> return;
> >>
> >> - InternalScopedString new_file_path(kMaxPathLength);
> >> + InternalMmapVector<char> new_file_path(kMaxPathLength);
> >> filename = FindFile(filename, new_file_path.data(), new_file_path.size());
> >>
> >> // Read the file.
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cpp
> >> index 710da4c1cec..98418b426c3 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cpp
> >> @@ -356,7 +356,7 @@ void ParseSymbolizePCOutput(const char *str, SymbolizedStack *res) {
> >> InternalFree(info->function);
> >> info->function = 0;
> >> }
> >> - if (0 == internal_strcmp(info->file, "??")) {
> >> + if (info->file && 0 == internal_strcmp(info->file, "??")) {
> >> InternalFree(info->file);
> >> info->file = 0;
> >> }
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_markup.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_markup.cpp
> >> index 30cba08ed53..01edef9c1aa 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_markup.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_markup.cpp
> >> @@ -54,6 +54,10 @@ bool Symbolizer::GetModuleNameAndOffsetForPC(uptr pc, const char **module_name,
> >> return false;
> >> }
> >>
> >> +// This is mainly used by hwasan for online symbolization. This isn't needed
> >> +// since hwasan can always just dump stack frames for offline symbolization.
> >> +bool Symbolizer::SymbolizeFrame(uptr addr, FrameInfo *info) { return false; }
> >> +
> >> // This is used in some places for suppression checking, which we
> >> // don't really support for Fuchsia. It's also used in UBSan to
> >> // identify a PC location to a function name, so we always fill in
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp
> >> index 4dd5cc3ad7c..4cd4b4636f0 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp
> >> @@ -400,11 +400,20 @@ const char *Symbolizer::PlatformDemangle(const char *name) {
> >>
> >> static SymbolizerTool *ChooseExternalSymbolizer(LowLevelAllocator *allocator) {
> >> const char *path = common_flags()->external_symbolizer_path;
> >> +
> >> + if (path && internal_strchr(path, '%')) {
> >> + char *new_path = (char *)InternalAlloc(kMaxPathLength);
> >> + SubstituteForFlagValue(path, new_path, kMaxPathLength);
> >> + path = new_path;
> >> + }
> >> +
> >> const char *binary_name = path ? StripModuleName(path) : "";
> >> + static const char kLLVMSymbolizerPrefix[] = "llvm-symbolizer";
> >> if (path && path[0] == '\0') {
> >> VReport(2, "External symbolizer is explicitly disabled.\n");
> >> return nullptr;
> >> - } else if (!internal_strcmp(binary_name, "llvm-symbolizer")) {
> >> + } else if (!internal_strncmp(binary_name, kLLVMSymbolizerPrefix,
> >> + internal_strlen(kLLVMSymbolizerPrefix))) {
> >> VReport(2, "Using llvm-symbolizer at user-specified path: %s\n", path);
> >> return new(*allocator) LLVMSymbolizer(path, allocator);
> >> } else if (!internal_strcmp(binary_name, "atos")) {
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_report.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_report.cpp
> >> index 06301b83ea1..9287993e665 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_report.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_report.cpp
> >> @@ -31,7 +31,7 @@ namespace __sanitizer {
> >> void ReportErrorSummary(const char *error_type, const AddressInfo &info,
> >> const char *alt_tool_name) {
> >> if (!common_flags()->print_summary) return;
> >> - InternalScopedString buff(kMaxSummaryLength);
> >> + InternalScopedString buff;
> >> buff.append("%s ", error_type);
> >> RenderFrame(&buff, "%L %F", 0, info.address, &info,
> >> common_flags()->symbolize_vs_style,
> >> @@ -150,7 +150,7 @@ static void PrintMemoryByte(InternalScopedString *str, const char *before,
> >> static void MaybeDumpInstructionBytes(uptr pc) {
> >> if (!common_flags()->dump_instruction_bytes || (pc < GetPageSizeCached()))
> >> return;
> >> - InternalScopedString str(1024);
> >> + InternalScopedString str;
> >> str.append("First 16 instruction bytes at pc: ");
> >> if (IsAccessibleMemoryRange(pc, 16)) {
> >> for (int i = 0; i < 16; ++i) {
> >> @@ -211,7 +211,7 @@ static void ReportDeadlySignalImpl(const SignalContext &sig, u32 tid,
> >> Report("The signal is caused by a %s memory access.\n", access_type);
> >> if (!sig.is_true_faulting_addr)
> >> Report("Hint: this fault was caused by a dereference of a high value "
> >> - "address (see register values below). Dissassemble the provided "
> >> + "address (see register values below). Disassemble the provided "
> >> "pc to learn which register was used.\n");
> >> else if (sig.addr < GetPageSizeCached())
> >> Report("Hint: address points to the zero page.\n");
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cpp
> >> index 48fa2d1033a..702d901353d 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cpp
> >> @@ -136,9 +136,10 @@ void InitializeDbgHelpIfNeeded() {
> >> bool WinSymbolizerTool::SymbolizePC(uptr addr, SymbolizedStack *frame) {
> >> InitializeDbgHelpIfNeeded();
> >>
> >> - // See http://msdn.microsoft.com/en-us/library/ms680578(VS.85).aspx
> >> - char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(CHAR)];
> >> - PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer;
> >> + // See https://docs.microsoft.com/en-us/windows/win32/debug/retrieving-symbol-information-by-address
> >> + InternalMmapVector<char> buffer(sizeof(SYMBOL_INFO) +
> >> + MAX_SYM_NAME * sizeof(CHAR));
> >> + PSYMBOL_INFO symbol = (PSYMBOL_INFO)&buffer[0];
> >> symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
> >> symbol->MaxNameLen = MAX_SYM_NAME;
> >> DWORD64 offset = 0;
> >> @@ -223,7 +224,7 @@ bool SymbolizerProcess::StartSymbolizerSubprocess() {
> >> // Compute the command line. Wrap double quotes around everything.
> >> const char *argv[kArgVMax];
> >> GetArgV(path_, argv);
> >> - InternalScopedString command_line(kMaxPathLength * 3);
> >> + InternalScopedString command_line;
> >> for (int i = 0; argv[i]; i++) {
> >> const char *arg = argv[i];
> >> int arglen = internal_strlen(arg);
> >> @@ -281,8 +282,15 @@ static void ChooseSymbolizerTools(IntrusiveList<SymbolizerTool> *list,
> >> return;
> >> }
> >>
> >> - // Add llvm-symbolizer in case the binary has dwarf.
> >> + // Add llvm-symbolizer.
> >> const char *user_path = common_flags()->external_symbolizer_path;
> >> +
> >> + if (user_path && internal_strchr(user_path, '%')) {
> >> + char *new_path = (char *)InternalAlloc(kMaxPathLength);
> >> + SubstituteForFlagValue(user_path, new_path, kMaxPathLength);
> >> + user_path = new_path;
> >> + }
> >> +
> >> const char *path =
> >> user_path ? user_path : FindPathToBinary("llvm-symbolizer.exe");
> >> if (path) {
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_termination.cpp b/libsanitizer/sanitizer_common/sanitizer_termination.cpp
> >> index 84be6fc3234..6a54734353c 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_termination.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_termination.cpp
> >> @@ -59,26 +59,31 @@ void NORETURN Die() {
> >> internal__exit(common_flags()->exitcode);
> >> }
> >>
> >> -static CheckFailedCallbackType CheckFailedCallback;
> >> -void SetCheckFailedCallback(CheckFailedCallbackType callback) {
> >> - CheckFailedCallback = callback;
> >> +static void (*CheckUnwindCallback)();
> >> +void SetCheckUnwindCallback(void (*callback)()) {
> >> + CheckUnwindCallback = callback;
> >> }
> >>
> >> -const int kSecondsToSleepWhenRecursiveCheckFailed = 2;
> >> -
> >> void NORETURN CheckFailed(const char *file, int line, const char *cond,
> >> u64 v1, u64 v2) {
> >> - static atomic_uint32_t num_calls;
> >> - if (atomic_fetch_add(&num_calls, 1, memory_order_relaxed) > 10) {
> >> - SleepForSeconds(kSecondsToSleepWhenRecursiveCheckFailed);
> >> + u32 tid = GetTid();
> >> + Printf("%s: CHECK failed: %s:%d \"%s\" (0x%zx, 0x%zx) (tid=%u)\n",
> >> + SanitizerToolName, StripModuleName(file), line, cond, (uptr)v1,
> >> + (uptr)v2, tid);
> >> + static atomic_uint32_t first_tid;
> >> + u32 cmp = 0;
> >> + if (!atomic_compare_exchange_strong(&first_tid, &cmp, tid,
> >> + memory_order_relaxed)) {
> >> + if (cmp == tid) {
> >> + // Recursing into CheckFailed.
> >> + } else {
> >> + // Another thread fails already, let it print the stack and terminate.
> >> + SleepForSeconds(2);
> >> + }
> >> Trap();
> >> }
> >> -
> >> - if (CheckFailedCallback) {
> >> - CheckFailedCallback(file, line, cond, v1, v2);
> >> - }
> >> - Report("Sanitizer CHECK failed: %s:%d %s (%lld, %lld)\n", file, line, cond,
> >> - v1, v2);
> >> + if (CheckUnwindCallback)
> >> + CheckUnwindCallback();
> >> Die();
> >> }
> >>
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_thread_registry.cpp b/libsanitizer/sanitizer_common/sanitizer_thread_registry.cpp
> >> index f2c6f279931..3273da38bfd 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_thread_registry.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_thread_registry.cpp
> >> @@ -85,7 +85,7 @@ void ThreadContextBase::SetCreated(uptr _user_id, u64 _unique_id,
> >> unique_id = _unique_id;
> >> detached = _detached;
> >> // Parent tid makes no sense for the main thread.
> >> - if (tid != 0)
> >> + if (tid != kMainTid)
> >> parent_tid = _parent_tid;
> >> OnCreated(arg);
> >> }
> >> @@ -99,8 +99,6 @@ void ThreadContextBase::Reset() {
> >>
> >> // ThreadRegistry implementation.
> >>
> >> -const u32 ThreadRegistry::kUnknownTid = ~0U;
> >> -
> >> ThreadRegistry::ThreadRegistry(ThreadContextFactory factory, u32 max_threads,
> >> u32 thread_quarantine_size, u32 max_reuse)
> >> : context_factory_(factory),
> >> @@ -135,7 +133,7 @@ uptr ThreadRegistry::GetMaxAliveThreads() {
> >> u32 ThreadRegistry::CreateThread(uptr user_id, bool detached, u32 parent_tid,
> >> void *arg) {
> >> BlockingMutexLock l(&mtx_);
> >> - u32 tid = kUnknownTid;
> >> + u32 tid = kInvalidTid;
> >> ThreadContextBase *tctx = QuarantinePop();
> >> if (tctx) {
> >> tid = tctx->tid;
> >> @@ -155,7 +153,7 @@ u32 ThreadRegistry::CreateThread(uptr user_id, bool detached, u32 parent_tid,
> >> Die();
> >> }
> >> CHECK_NE(tctx, 0);
> >> - CHECK_NE(tid, kUnknownTid);
> >> + CHECK_NE(tid, kInvalidTid);
> >> CHECK_LT(tid, max_threads_);
> >> CHECK_EQ(tctx->status, ThreadStatusInvalid);
> >> alive_threads_++;
> >> @@ -186,7 +184,7 @@ u32 ThreadRegistry::FindThread(FindThreadCallback cb, void *arg) {
> >> if (tctx != 0 && cb(tctx, arg))
> >> return tctx->tid;
> >> }
> >> - return kUnknownTid;
> >> + return kInvalidTid;
> >> }
> >>
> >> ThreadContextBase *
> >> @@ -278,7 +276,7 @@ void ThreadRegistry::JoinThread(u32 tid, void *arg) {
> >> // really started. We just did CreateThread for a prospective new
> >> // thread before trying to create it, and then failed to actually
> >> // create it, and so never called StartThread.
> >> -void ThreadRegistry::FinishThread(u32 tid) {
> >> +ThreadStatus ThreadRegistry::FinishThread(u32 tid) {
> >> BlockingMutexLock l(&mtx_);
> >> CHECK_GT(alive_threads_, 0);
> >> alive_threads_--;
> >> @@ -286,6 +284,7 @@ void ThreadRegistry::FinishThread(u32 tid) {
> >> ThreadContextBase *tctx = threads_[tid];
> >> CHECK_NE(tctx, 0);
> >> bool dead = tctx->detached;
> >> + ThreadStatus prev_status = tctx->status;
> >> if (tctx->status == ThreadStatusRunning) {
> >> CHECK_GT(running_threads_, 0);
> >> running_threads_--;
> >> @@ -300,6 +299,7 @@ void ThreadRegistry::FinishThread(u32 tid) {
> >> QuarantinePush(tctx);
> >> }
> >> tctx->SetDestroyed();
> >> + return prev_status;
> >> }
> >>
> >> void ThreadRegistry::StartThread(u32 tid, tid_t os_id, ThreadType thread_type,
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_thread_registry.h b/libsanitizer/sanitizer_common/sanitizer_thread_registry.h
> >> index 85c522a31ca..dcd445c28ae 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_thread_registry.h
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_thread_registry.h
> >> @@ -87,8 +87,6 @@ typedef ThreadContextBase* (*ThreadContextFactory)(u32 tid);
> >>
> >> class ThreadRegistry {
> >> public:
> >> - static const u32 kUnknownTid;
> >> -
> >> ThreadRegistry(ThreadContextFactory factory, u32 max_threads,
> >> u32 thread_quarantine_size, u32 max_reuse = 0);
> >> void GetNumberOfThreads(uptr *total = nullptr, uptr *running = nullptr,
> >> @@ -113,7 +111,7 @@ class ThreadRegistry {
> >> void RunCallbackForEachThreadLocked(ThreadCallback cb, void *arg);
> >>
> >> typedef bool (*FindThreadCallback)(ThreadContextBase *tctx, void *arg);
> >> - // Finds a thread using the provided callback. Returns kUnknownTid if no
> >> + // Finds a thread using the provided callback. Returns kInvalidTid if no
> >> // thread is found.
> >> u32 FindThread(FindThreadCallback cb, void *arg);
> >> // Should be guarded by ThreadRegistryLock. Return 0 if no thread
> >> @@ -126,7 +124,8 @@ class ThreadRegistry {
> >> void SetThreadNameByUserId(uptr user_id, const char *name);
> >> void DetachThread(u32 tid, void *arg);
> >> void JoinThread(u32 tid, void *arg);
> >> - void FinishThread(u32 tid);
> >> + // Finishes thread and returns previous status.
> >> + ThreadStatus FinishThread(u32 tid);
> >> void StartThread(u32 tid, tid_t os_id, ThreadType thread_type, void *arg);
> >> void SetThreadUserId(u32 tid, uptr user_id);
> >>
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.cpp b/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.cpp
> >> index 10748f96420..1f664b6cf5b 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.cpp
> >> @@ -12,6 +12,7 @@
> >>
> >> #include "sanitizer_tls_get_addr.h"
> >>
> >> +#include "sanitizer_atomic.h"
> >> #include "sanitizer_flags.h"
> >> #include "sanitizer_platform_interceptors.h"
> >>
> >> @@ -42,39 +43,54 @@ static atomic_uintptr_t number_of_live_dtls;
> >>
> >> static const uptr kDestroyedThread = -1;
> >>
> >> -static inline void DTLS_Deallocate(DTLS::DTV *dtv, uptr size) {
> >> - if (!size) return;
> >> - VReport(2, "__tls_get_addr: DTLS_Deallocate %p %zd\n", dtv, size);
> >> - UnmapOrDie(dtv, size * sizeof(DTLS::DTV));
> >> +static void DTLS_Deallocate(DTLS::DTVBlock *block) {
> >> + VReport(2, "__tls_get_addr: DTLS_Deallocate %p %zd\n", block);
> >> + UnmapOrDie(block, sizeof(DTLS::DTVBlock));
> >> atomic_fetch_sub(&number_of_live_dtls, 1, memory_order_relaxed);
> >> }
> >>
> >> -static inline void DTLS_Resize(uptr new_size) {
> >> - if (dtls.dtv_size >= new_size) return;
> >> - new_size = RoundUpToPowerOfTwo(new_size);
> >> - new_size = Max(new_size, 4096UL / sizeof(DTLS::DTV));
> >> - DTLS::DTV *new_dtv =
> >> - (DTLS::DTV *)MmapOrDie(new_size * sizeof(DTLS::DTV), "DTLS_Resize");
> >> +static DTLS::DTVBlock *DTLS_NextBlock(atomic_uintptr_t *cur) {
> >> + uptr v = atomic_load(cur, memory_order_acquire);
> >> + if (v == kDestroyedThread)
> >> + return nullptr;
> >> + DTLS::DTVBlock *next = (DTLS::DTVBlock *)v;
> >> + if (next)
> >> + return next;
> >> + DTLS::DTVBlock *new_dtv =
> >> + (DTLS::DTVBlock *)MmapOrDie(sizeof(DTLS::DTVBlock), "DTLS_NextBlock");
> >> + uptr prev = 0;
> >> + if (!atomic_compare_exchange_strong(cur, &prev, (uptr)new_dtv,
> >> + memory_order_seq_cst)) {
> >> + UnmapOrDie(new_dtv, sizeof(DTLS::DTVBlock));
> >> + return (DTLS::DTVBlock *)prev;
> >> + }
> >> uptr num_live_dtls =
> >> atomic_fetch_add(&number_of_live_dtls, 1, memory_order_relaxed);
> >> - VReport(2, "__tls_get_addr: DTLS_Resize %p %zd\n", &dtls, num_live_dtls);
> >> - CHECK_LT(num_live_dtls, 1 << 20);
> >> - uptr old_dtv_size = dtls.dtv_size;
> >> - DTLS::DTV *old_dtv = dtls.dtv;
> >> - if (old_dtv_size)
> >> - internal_memcpy(new_dtv, dtls.dtv, dtls.dtv_size * sizeof(DTLS::DTV));
> >> - dtls.dtv = new_dtv;
> >> - dtls.dtv_size = new_size;
> >> - if (old_dtv_size)
> >> - DTLS_Deallocate(old_dtv, old_dtv_size);
> >> + VReport(2, "__tls_get_addr: DTLS_NextBlock %p %zd\n", &dtls, num_live_dtls);
> >> + return new_dtv;
> >> +}
> >> +
> >> +static DTLS::DTV *DTLS_Find(uptr id) {
> >> + VReport(2, "__tls_get_addr: DTLS_Find %p %zd\n", &dtls, id);
> >> + static constexpr uptr kPerBlock = ARRAY_SIZE(DTLS::DTVBlock::dtvs);
> >> + DTLS::DTVBlock *cur = DTLS_NextBlock(&dtls.dtv_block);
> >> + if (!cur)
> >> + return nullptr;
> >> + for (; id >= kPerBlock; id -= kPerBlock) cur = DTLS_NextBlock(&cur->next);
> >> + return cur->dtvs + id;
> >> }
> >>
> >> void DTLS_Destroy() {
> >> if (!common_flags()->intercept_tls_get_addr) return;
> >> - VReport(2, "__tls_get_addr: DTLS_Destroy %p %zd\n", &dtls, dtls.dtv_size);
> >> - uptr s = dtls.dtv_size;
> >> - dtls.dtv_size = kDestroyedThread; // Do this before unmap for AS-safety.
> >> - DTLS_Deallocate(dtls.dtv, s);
> >> + VReport(2, "__tls_get_addr: DTLS_Destroy %p\n", &dtls);
> >> + DTLS::DTVBlock *block = (DTLS::DTVBlock *)atomic_exchange(
> >> + &dtls.dtv_block, kDestroyedThread, memory_order_release);
> >> + while (block) {
> >> + DTLS::DTVBlock *next =
> >> + (DTLS::DTVBlock *)atomic_load(&block->next, memory_order_acquire);
> >> + DTLS_Deallocate(block);
> >> + block = next;
> >> + }
> >> }
> >>
> >> #if defined(__powerpc64__) || defined(__mips__)
> >> @@ -96,9 +112,9 @@ DTLS::DTV *DTLS_on_tls_get_addr(void *arg_void, void *res,
> >> if (!common_flags()->intercept_tls_get_addr) return 0;
> >> TlsGetAddrParam *arg = reinterpret_cast<TlsGetAddrParam *>(arg_void);
> >> uptr dso_id = arg->dso_id;
> >> - if (dtls.dtv_size == kDestroyedThread) return 0;
> >> - DTLS_Resize(dso_id + 1);
> >> - if (dtls.dtv[dso_id].beg) return 0;
> >> + DTLS::DTV *dtv = DTLS_Find(dso_id);
> >> + if (!dtv || dtv->beg)
> >> + return 0;
> >> uptr tls_size = 0;
> >> uptr tls_beg = reinterpret_cast<uptr>(res) - arg->offset - kDtvOffset;
> >> VReport(2, "__tls_get_addr: %p {%p,%p} => %p; tls_beg: %p; sp: %p "
> >> @@ -126,9 +142,9 @@ DTLS::DTV *DTLS_on_tls_get_addr(void *arg_void, void *res,
> >> // This may happen inside the DTOR of main thread, so just ignore it.
> >> tls_size = 0;
> >> }
> >> - dtls.dtv[dso_id].beg = tls_beg;
> >> - dtls.dtv[dso_id].size = tls_size;
> >> - return dtls.dtv + dso_id;
> >> + dtv->beg = tls_beg;
> >> + dtv->size = tls_size;
> >> + return dtv;
> >> }
> >>
> >> void DTLS_on_libc_memalign(void *ptr, uptr size) {
> >> @@ -141,7 +157,8 @@ void DTLS_on_libc_memalign(void *ptr, uptr size) {
> >> DTLS *DTLS_Get() { return &dtls; }
> >>
> >> bool DTLSInDestruction(DTLS *dtls) {
> >> - return dtls->dtv_size == kDestroyedThread;
> >> + return atomic_load(&dtls->dtv_block, memory_order_relaxed) ==
> >> + kDestroyedThread;
> >> }
> >>
> >> #else
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.h b/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.h
> >> index c7cd5a8bffc..a599c0bbc75 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.h
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.h
> >> @@ -28,6 +28,7 @@
> >> #ifndef SANITIZER_TLS_GET_ADDR_H
> >> #define SANITIZER_TLS_GET_ADDR_H
> >>
> >> +#include "sanitizer_atomic.h"
> >> #include "sanitizer_common.h"
> >>
> >> namespace __sanitizer {
> >> @@ -38,15 +39,31 @@ struct DTLS {
> >> struct DTV {
> >> uptr beg, size;
> >> };
> >> + struct DTVBlock {
> >> + atomic_uintptr_t next;
> >> + DTV dtvs[(4096UL - sizeof(next)) / sizeof(DTLS::DTV)];
> >> + };
> >> +
> >> + static_assert(sizeof(DTVBlock) <= 4096UL, "Unexpected block size");
> >>
> >> - uptr dtv_size;
> >> - DTV *dtv; // dtv_size elements, allocated by MmapOrDie.
> >> + atomic_uintptr_t dtv_block;
> >>
> >> // Auxiliary fields, don't access them outside sanitizer_tls_get_addr.cpp
> >> uptr last_memalign_size;
> >> uptr last_memalign_ptr;
> >> };
> >>
> >> +template <typename Fn>
> >> +void ForEachDVT(DTLS *dtls, const Fn &fn) {
> >> + DTLS::DTVBlock *block =
> >> + (DTLS::DTVBlock *)atomic_load(&dtls->dtv_block, memory_order_acquire);
> >> + while (block) {
> >> + int id = 0;
> >> + for (auto &d : block->dtvs) fn(d, id++);
> >> + block = (DTLS::DTVBlock *)atomic_load(&block->next, memory_order_acquire);
> >> + }
> >> +}
> >> +
> >> // Returns pointer and size of a linker-allocated TLS block.
> >> // Each block is returned exactly once.
> >> DTLS::DTV *DTLS_on_tls_get_addr(void *arg, void *res, uptr static_tls_begin,
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_unwind_win.cpp b/libsanitizer/sanitizer_common/sanitizer_unwind_win.cpp
> >> index e2edf428004..7e01c81d042 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_unwind_win.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_unwind_win.cpp
> >> @@ -43,6 +43,10 @@ void BufferedStackTrace::UnwindSlow(uptr pc, u32 max_depth) {
> >> trace_buffer[0] = pc;
> >> }
> >>
> >> +#ifdef __clang__
> >> +#pragma clang diagnostic push
> >> +#pragma clang diagnostic ignored "-Wframe-larger-than="
> >> +#endif
> >> void BufferedStackTrace::UnwindSlow(uptr pc, void *context, u32 max_depth) {
> >> CHECK(context);
> >> CHECK_GE(max_depth, 2);
> >> @@ -74,6 +78,9 @@ void BufferedStackTrace::UnwindSlow(uptr pc, void *context, u32 max_depth) {
> >> trace_buffer[size++] = (uptr)stack_frame.AddrPC.Offset;
> >> }
> >> }
> >> +#ifdef __clang__
> >> +#pragma clang diagnostic pop
> >> +#endif
> >> #endif // #if !SANITIZER_GO
> >>
> >> #endif // SANITIZER_WINDOWS
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_win.cpp b/libsanitizer/sanitizer_common/sanitizer_win.cpp
> >> index 85ac2633bde..f383e130fa5 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_win.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_win.cpp
> >> @@ -334,8 +334,12 @@ bool MprotectNoAccess(uptr addr, uptr size) {
> >> }
> >>
> >> void ReleaseMemoryPagesToOS(uptr beg, uptr end) {
> >> - // This is almost useless on 32-bits.
> >> - // FIXME: add madvise-analog when we move to 64-bits.
> >> + uptr beg_aligned = RoundDownTo(beg, GetPageSizeCached()),
> >> + end_aligned = RoundDownTo(end, GetPageSizeCached());
> >> + CHECK(beg < end); // make sure the region is sane
> >> + if (beg_aligned == end_aligned) // make sure we're freeing at least 1 page;
> >> + return;
> >> + UnmapOrDie((void *)beg, end_aligned - beg_aligned);
> >> }
> >>
> >> void SetShadowRegionHugePageMode(uptr addr, uptr size) {
> >> @@ -386,6 +390,12 @@ uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding,
> >> return 0;
> >> }
> >>
> >> +uptr MapDynamicShadowAndAliases(uptr shadow_size, uptr alias_size,
> >> + uptr num_aliases, uptr ring_buffer_size) {
> >> + CHECK(false && "HWASan aliasing is unimplemented on Windows");
> >> + return 0;
> >> +}
> >> +
> >> bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) {
> >> MEMORY_BASIC_INFORMATION mbi;
> >> CHECK(VirtualQuery((void *)range_start, &mbi, sizeof(mbi)));
> >> @@ -564,7 +574,7 @@ void Abort() {
> >> // load the image at this address. Therefore, we call it the preferred base. Any
> >> // addresses in the DWARF typically assume that the object has been loaded at
> >> // this address.
> >> -static uptr GetPreferredBase(const char *modname) {
> >> +static uptr GetPreferredBase(const char *modname, char *buf, size_t buf_size) {
> >> fd_t fd = OpenFile(modname, RdOnly, nullptr);
> >> if (fd == kInvalidFd)
> >> return 0;
> >> @@ -586,12 +596,10 @@ static uptr GetPreferredBase(const char *modname) {
> >> // IMAGE_FILE_HEADER
> >> // IMAGE_OPTIONAL_HEADER
> >> // Seek to e_lfanew and read all that data.
> >> - char buf[4 + sizeof(IMAGE_FILE_HEADER) + sizeof(IMAGE_OPTIONAL_HEADER)];
> >> if (::SetFilePointer(fd, dos_header.e_lfanew, nullptr, FILE_BEGIN) ==
> >> INVALID_SET_FILE_POINTER)
> >> return 0;
> >> - if (!ReadFromFile(fd, &buf[0], sizeof(buf), &bytes_read) ||
> >> - bytes_read != sizeof(buf))
> >> + if (!ReadFromFile(fd, buf, buf_size, &bytes_read) || bytes_read != buf_size)
> >> return 0;
> >>
> >> // Check for "PE\0\0" before the PE header.
> >> @@ -633,6 +641,10 @@ void ListOfModules::init() {
> >> }
> >> }
> >>
> >> + InternalMmapVector<char> buf(4 + sizeof(IMAGE_FILE_HEADER) +
> >> + sizeof(IMAGE_OPTIONAL_HEADER));
> >> + InternalMmapVector<wchar_t> modname_utf16(kMaxPathLength);
> >> + InternalMmapVector<char> module_name(kMaxPathLength);
> >> // |num_modules| is the number of modules actually present,
> >> size_t num_modules = bytes_required / sizeof(HMODULE);
> >> for (size_t i = 0; i < num_modules; ++i) {
> >> @@ -642,15 +654,13 @@ void ListOfModules::init() {
> >> continue;
> >>
> >> // Get the UTF-16 path and convert to UTF-8.
> >> - wchar_t modname_utf16[kMaxPathLength];
> >> int modname_utf16_len =
> >> - GetModuleFileNameW(handle, modname_utf16, kMaxPathLength);
> >> + GetModuleFileNameW(handle, &modname_utf16[0], kMaxPathLength);
> >> if (modname_utf16_len == 0)
> >> modname_utf16[0] = '\0';
> >> - char module_name[kMaxPathLength];
> >> - int module_name_len =
> >> - ::WideCharToMultiByte(CP_UTF8, 0, modname_utf16, modname_utf16_len + 1,
> >> - &module_name[0], kMaxPathLength, NULL, NULL);
> >> + int module_name_len = ::WideCharToMultiByte(
> >> + CP_UTF8, 0, &modname_utf16[0], modname_utf16_len + 1, &module_name[0],
> >> + kMaxPathLength, NULL, NULL);
> >> module_name[module_name_len] = '\0';
> >>
> >> uptr base_address = (uptr)mi.lpBaseOfDll;
> >> @@ -660,15 +670,16 @@ void ListOfModules::init() {
> >> // RVA when computing the module offset. This helps llvm-symbolizer find the
> >> // right DWARF CU. In the common case that the image is loaded at it's
> >> // preferred address, we will now print normal virtual addresses.
> >> - uptr preferred_base = GetPreferredBase(&module_name[0]);
> >> + uptr preferred_base =
> >> + GetPreferredBase(&module_name[0], &buf[0], buf.size());
> >> uptr adjusted_base = base_address - preferred_base;
> >>
> >> - LoadedModule cur_module;
> >> - cur_module.set(module_name, adjusted_base);
> >> + modules_.push_back(LoadedModule());
> >> + LoadedModule &cur_module = modules_.back();
> >> + cur_module.set(&module_name[0], adjusted_base);
> >> // We add the whole module as one single address range.
> >> cur_module.addAddressRange(base_address, end_address, /*executable*/ true,
> >> /*writable*/ true);
> >> - modules_.push_back(cur_module);
> >> }
> >> UnmapOrDie(hmodules, modules_buffer_size);
> >> }
> >> @@ -956,22 +967,27 @@ void SignalContext::InitPcSpBp() {
> >>
> >> uptr SignalContext::GetAddress() const {
> >> EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD *)siginfo;
> >> - return exception_record->ExceptionInformation[1];
> >> + if (exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
> >> + return exception_record->ExceptionInformation[1];
> >> + return (uptr)exception_record->ExceptionAddress;
> >> }
> >>
> >> bool SignalContext::IsMemoryAccess() const {
> >> - return GetWriteFlag() != SignalContext::UNKNOWN;
> >> + return ((EXCEPTION_RECORD *)siginfo)->ExceptionCode ==
> >> + EXCEPTION_ACCESS_VIOLATION;
> >> }
> >>
> >> -bool SignalContext::IsTrueFaultingAddress() const {
> >> - // FIXME: Provide real implementation for this. See Linux and Mac variants.
> >> - return IsMemoryAccess();
> >> -}
> >> +bool SignalContext::IsTrueFaultingAddress() const { return true; }
> >>
> >> SignalContext::WriteFlag SignalContext::GetWriteFlag() const {
> >> EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD *)siginfo;
> >> +
> >> + // The write flag is only available for access violation exceptions.
> >> + if (exception_record->ExceptionCode != EXCEPTION_ACCESS_VIOLATION)
> >> + return SignalContext::UNKNOWN;
> >> +
> >> // The contents of this array are documented at
> >> - // https://msdn.microsoft.com/en-us/library/windows/desktop/aa363082(v=vs.85).aspx
> >> + // https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-exception_record
> >> // The first element indicates read as 0, write as 1, or execute as 8. The
> >> // second element is the faulting address.
> >> switch (exception_record->ExceptionInformation[0]) {
> >> @@ -1037,10 +1053,24 @@ const char *SignalContext::Describe() const {
> >> }
> >>
> >> uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {
> >> - // FIXME: Actually implement this function.
> >> - CHECK_GT(buf_len, 0);
> >> - buf[0] = 0;
> >> - return 0;
> >> + if (buf_len == 0)
> >> + return 0;
> >> +
> >> + // Get the UTF-16 path and convert to UTF-8.
> >> + InternalMmapVector<wchar_t> binname_utf16(kMaxPathLength);
> >> + int binname_utf16_len =
> >> + GetModuleFileNameW(NULL, &binname_utf16[0], kMaxPathLength);
> >> + if (binname_utf16_len == 0) {
> >> + buf[0] = '\0';
> >> + return 0;
> >> + }
> >> + int binary_name_len =
> >> + ::WideCharToMultiByte(CP_UTF8, 0, &binname_utf16[0], binname_utf16_len,
> >> + buf, buf_len, NULL, NULL);
> >> + if ((unsigned)binary_name_len == buf_len)
> >> + --binary_name_len;
> >> + buf[binary_name_len] = '\0';
> >> + return binary_name_len;
> >> }
> >>
> >> uptr ReadLongProcessName(/*out*/char *buf, uptr buf_len) {
> >> diff --git a/libsanitizer/tsan/tsan_clock.cpp b/libsanitizer/tsan/tsan_clock.cpp
> >> index c91b29cb22b..8e5188392ca 100644
> >> --- a/libsanitizer/tsan/tsan_clock.cpp
> >> +++ b/libsanitizer/tsan/tsan_clock.cpp
> >> @@ -150,7 +150,7 @@ void ThreadClock::acquire(ClockCache *c, SyncClock *src) {
> >> bool acquired = false;
> >> for (unsigned i = 0; i < kDirtyTids; i++) {
> >> SyncClock::Dirty dirty = src->dirty_[i];
> >> - unsigned tid = dirty.tid;
> >> + unsigned tid = dirty.tid();
> >> if (tid != kInvalidTid) {
> >> if (clk_[tid] < dirty.epoch) {
> >> clk_[tid] = dirty.epoch;
> >> @@ -299,10 +299,10 @@ void ThreadClock::ReleaseStore(ClockCache *c, SyncClock *dst) {
> >> dst->tab_idx_ = cached_idx_;
> >> dst->size_ = cached_size_;
> >> dst->blocks_ = cached_blocks_;
> >> - CHECK_EQ(dst->dirty_[0].tid, kInvalidTid);
> >> + CHECK_EQ(dst->dirty_[0].tid(), kInvalidTid);
> >> // The cached clock is shared (immutable),
> >> // so this is where we store the current clock.
> >> - dst->dirty_[0].tid = tid_;
> >> + dst->dirty_[0].set_tid(tid_);
> >> dst->dirty_[0].epoch = clk_[tid_];
> >> dst->release_store_tid_ = tid_;
> >> dst->release_store_reused_ = reused_;
> >> @@ -336,8 +336,7 @@ void ThreadClock::ReleaseStore(ClockCache *c, SyncClock *dst) {
> >> ce.reused = 0;
> >> i++;
> >> }
> >> - for (uptr i = 0; i < kDirtyTids; i++)
> >> - dst->dirty_[i].tid = kInvalidTid;
> >> + for (uptr i = 0; i < kDirtyTids; i++) dst->dirty_[i].set_tid(kInvalidTid);
> >> dst->release_store_tid_ = tid_;
> >> dst->release_store_reused_ = reused_;
> >> // Rememeber that we don't need to acquire it in future.
> >> @@ -369,10 +368,10 @@ void ThreadClock::UpdateCurrentThread(ClockCache *c, SyncClock *dst) const {
> >> // Update the threads time, but preserve 'acquired' flag.
> >> for (unsigned i = 0; i < kDirtyTids; i++) {
> >> SyncClock::Dirty *dirty = &dst->dirty_[i];
> >> - const unsigned tid = dirty->tid;
> >> + const unsigned tid = dirty->tid();
> >> if (tid == tid_ || tid == kInvalidTid) {
> >> CPP_STAT_INC(StatClockReleaseFast);
> >> - dirty->tid = tid_;
> >> + dirty->set_tid(tid_);
> >> dirty->epoch = clk_[tid_];
> >> return;
> >> }
> >> @@ -393,8 +392,8 @@ bool ThreadClock::IsAlreadyAcquired(const SyncClock *src) const {
> >> return false;
> >> for (unsigned i = 0; i < kDirtyTids; i++) {
> >> SyncClock::Dirty dirty = src->dirty_[i];
> >> - if (dirty.tid != kInvalidTid) {
> >> - if (clk_[dirty.tid] < dirty.epoch)
> >> + if (dirty.tid() != kInvalidTid) {
> >> + if (clk_[dirty.tid()] < dirty.epoch)
> >> return false;
> >> }
> >> }
> >> @@ -453,8 +452,7 @@ void SyncClock::ResetImpl() {
> >> blocks_ = 0;
> >> release_store_tid_ = kInvalidTid;
> >> release_store_reused_ = 0;
> >> - for (uptr i = 0; i < kDirtyTids; i++)
> >> - dirty_[i].tid = kInvalidTid;
> >> + for (uptr i = 0; i < kDirtyTids; i++) dirty_[i].set_tid(kInvalidTid);
> >> }
> >>
> >> void SyncClock::Resize(ClockCache *c, uptr nclk) {
> >> @@ -503,10 +501,10 @@ void SyncClock::Resize(ClockCache *c, uptr nclk) {
> >> void SyncClock::FlushDirty() {
> >> for (unsigned i = 0; i < kDirtyTids; i++) {
> >> Dirty *dirty = &dirty_[i];
> >> - if (dirty->tid != kInvalidTid) {
> >> - CHECK_LT(dirty->tid, size_);
> >> - elem(dirty->tid).epoch = dirty->epoch;
> >> - dirty->tid = kInvalidTid;
> >> + if (dirty->tid() != kInvalidTid) {
> >> + CHECK_LT(dirty->tid(), size_);
> >> + elem(dirty->tid()).epoch = dirty->epoch;
> >> + dirty->set_tid(kInvalidTid);
> >> }
> >> }
> >> }
> >> @@ -559,7 +557,7 @@ ALWAYS_INLINE bool SyncClock::Cachable() const {
> >> if (size_ == 0)
> >> return false;
> >> for (unsigned i = 0; i < kDirtyTids; i++) {
> >> - if (dirty_[i].tid != kInvalidTid)
> >> + if (dirty_[i].tid() != kInvalidTid)
> >> return false;
> >> }
> >> return atomic_load_relaxed(ref_ptr(tab_)) == 1;
> >> @@ -606,7 +604,7 @@ ALWAYS_INLINE void SyncClock::append_block(u32 idx) {
> >> u64 SyncClock::get(unsigned tid) const {
> >> for (unsigned i = 0; i < kDirtyTids; i++) {
> >> Dirty dirty = dirty_[i];
> >> - if (dirty.tid == tid)
> >> + if (dirty.tid() == tid)
> >> return dirty.epoch;
> >> }
> >> return elem(tid).epoch;
> >> @@ -625,9 +623,8 @@ void SyncClock::DebugDump(int(*printf)(const char *s, ...)) {
> >> for (uptr i = 0; i < size_; i++)
> >> printf("%s%llu", i == 0 ? "" : ",", elem(i).reused);
> >> printf("] release_store_tid=%d/%d dirty_tids=%d[%llu]/%d[%llu]",
> >> - release_store_tid_, release_store_reused_,
> >> - dirty_[0].tid, dirty_[0].epoch,
> >> - dirty_[1].tid, dirty_[1].epoch);
> >> + release_store_tid_, release_store_reused_, dirty_[0].tid(),
> >> + dirty_[0].epoch, dirty_[1].tid(), dirty_[1].epoch);
> >> }
> >>
> >> void SyncClock::Iter::Next() {
> >> diff --git a/libsanitizer/tsan/tsan_clock.h b/libsanitizer/tsan/tsan_clock.h
> >> index 736cdae06ba..31376a1bc9e 100644
> >> --- a/libsanitizer/tsan/tsan_clock.h
> >> +++ b/libsanitizer/tsan/tsan_clock.h
> >> @@ -17,7 +17,7 @@
> >>
> >> namespace __tsan {
> >>
> >> -typedef DenseSlabAlloc<ClockBlock, 1<<16, 1<<10> ClockAlloc;
> >> +typedef DenseSlabAlloc<ClockBlock, 1 << 22, 1 << 10> ClockAlloc;
> >> typedef DenseSlabAllocCache ClockCache;
> >>
> >> // The clock that lives in sync variables (mutexes, atomics, etc).
> >> @@ -65,10 +65,20 @@ class SyncClock {
> >> static const uptr kDirtyTids = 2;
> >>
> >> struct Dirty {
> >> - u64 epoch : kClkBits;
> >> - u64 tid : 64 - kClkBits; // kInvalidId if not active
> >> + u32 tid() const { return tid_ == kShortInvalidTid ? kInvalidTid : tid_; }
> >> + void set_tid(u32 tid) {
> >> + tid_ = tid == kInvalidTid ? kShortInvalidTid : tid;
> >> + }
> >> + u64 epoch : kClkBits;
> >> +
> >> + private:
> >> + // Full kInvalidTid won't fit into Dirty::tid.
> >> + static const u64 kShortInvalidTid = (1ull << (64 - kClkBits)) - 1;
> >> + u64 tid_ : 64 - kClkBits; // kInvalidId if not active
> >> };
> >>
> >> + static_assert(sizeof(Dirty) == 8, "Dirty is not 64bit");
> >> +
> >> unsigned release_store_tid_;
> >> unsigned release_store_reused_;
> >> Dirty dirty_[kDirtyTids];
> >> diff --git a/libsanitizer/tsan/tsan_defs.h b/libsanitizer/tsan/tsan_defs.h
> >> index 293d7deccc3..f53787aeba9 100644
> >> --- a/libsanitizer/tsan/tsan_defs.h
> >> +++ b/libsanitizer/tsan/tsan_defs.h
> >> @@ -98,8 +98,6 @@ const bool kCollectHistory = false;
> >> const bool kCollectHistory = true;
> >> #endif
> >>
> >> -const u16 kInvalidTid = kMaxTid + 1;
> >> -
> >> // The following "build consistency" machinery ensures that all source files
> >> // are built in the same configuration. Inconsistent builds lead to
> >> // hard to debug crashes.
> >> diff --git a/libsanitizer/tsan/tsan_dense_alloc.h b/libsanitizer/tsan/tsan_dense_alloc.h
> >> index 64fc50e95c2..6c89e405980 100644
> >> --- a/libsanitizer/tsan/tsan_dense_alloc.h
> >> +++ b/libsanitizer/tsan/tsan_dense_alloc.h
> >> @@ -29,28 +29,40 @@ class DenseSlabAllocCache {
> >> typedef u32 IndexT;
> >> uptr pos;
> >> IndexT cache[kSize];
> >> - template<typename T, uptr kL1Size, uptr kL2Size> friend class DenseSlabAlloc;
> >> + template <typename, uptr, uptr, u64>
> >> + friend class DenseSlabAlloc;
> >> };
> >>
> >> -template<typename T, uptr kL1Size, uptr kL2Size>
> >> +template <typename T, uptr kL1Size, uptr kL2Size, u64 kReserved = 0>
> >> class DenseSlabAlloc {
> >> public:
> >> typedef DenseSlabAllocCache Cache;
> >> typedef typename Cache::IndexT IndexT;
> >>
> >> - explicit DenseSlabAlloc(const char *name) {
> >> - // Check that kL1Size and kL2Size are sane.
> >> - CHECK_EQ(kL1Size & (kL1Size - 1), 0);
> >> - CHECK_EQ(kL2Size & (kL2Size - 1), 0);
> >> - CHECK_GE(1ull << (sizeof(IndexT) * 8), kL1Size * kL2Size);
> >> - // Check that it makes sense to use the dense alloc.
> >> - CHECK_GE(sizeof(T), sizeof(IndexT));
> >> - internal_memset(map_, 0, sizeof(map_));
> >> + static_assert((kL1Size & (kL1Size - 1)) == 0,
> >> + "kL1Size must be a power-of-two");
> >> + static_assert((kL2Size & (kL2Size - 1)) == 0,
> >> + "kL2Size must be a power-of-two");
> >> + static_assert((kL1Size * kL2Size) <= (1ull << (sizeof(IndexT) * 8)),
> >> + "kL1Size/kL2Size are too large");
> >> + static_assert(((kL1Size * kL2Size - 1) & kReserved) == 0,
> >> + "reserved bits don't fit");
> >> + static_assert(sizeof(T) > sizeof(IndexT),
> >> + "it doesn't make sense to use dense alloc");
> >> +
> >> + explicit DenseSlabAlloc(LinkerInitialized, const char *name) {
> >> freelist_ = 0;
> >> fillpos_ = 0;
> >> name_ = name;
> >> }
> >>
> >> + explicit DenseSlabAlloc(const char *name)
> >> + : DenseSlabAlloc(LINKER_INITIALIZED, name) {
> >> + // It can be very large.
> >> + // Don't page it in for linker initialized objects.
> >> + internal_memset(map_, 0, sizeof(map_));
> >> + }
> >> +
> >> ~DenseSlabAlloc() {
> >> for (uptr i = 0; i < kL1Size; i++) {
> >> if (map_[i] != 0)
> >> diff --git a/libsanitizer/tsan/tsan_external.cpp b/libsanitizer/tsan/tsan_external.cpp
> >> index 466b2bf0f66..a87e12f2936 100644
> >> --- a/libsanitizer/tsan/tsan_external.cpp
> >> +++ b/libsanitizer/tsan/tsan_external.cpp
> >> @@ -111,12 +111,12 @@ void __tsan_external_assign_tag(void *addr, void *tag) {
> >>
> >> SANITIZER_INTERFACE_ATTRIBUTE
> >> void __tsan_external_read(void *addr, void *caller_pc, void *tag) {
> >> - ExternalAccess(addr, STRIP_PC(caller_pc), tag, MemoryRead);
> >> + ExternalAccess(addr, STRIP_PAC_PC(caller_pc), tag, MemoryRead);
> >> }
> >>
> >> SANITIZER_INTERFACE_ATTRIBUTE
> >> void __tsan_external_write(void *addr, void *caller_pc, void *tag) {
> >> - ExternalAccess(addr, STRIP_PC(caller_pc), tag, MemoryWrite);
> >> + ExternalAccess(addr, STRIP_PAC_PC(caller_pc), tag, MemoryWrite);
> >> }
> >> } // extern "C"
> >>
> >> diff --git a/libsanitizer/tsan/tsan_interceptors_mac.cpp b/libsanitizer/tsan/tsan_interceptors_mac.cpp
> >> index aa29536d861..ed10fccc980 100644
> >> --- a/libsanitizer/tsan/tsan_interceptors_mac.cpp
> >> +++ b/libsanitizer/tsan/tsan_interceptors_mac.cpp
> >> @@ -438,6 +438,7 @@ struct fake_shared_weak_count {
> >> virtual void on_zero_shared() = 0;
> >> virtual void _unused_0x18() = 0;
> >> virtual void on_zero_shared_weak() = 0;
> >> + virtual ~fake_shared_weak_count() = 0; // suppress -Wnon-virtual-dtor
> >> };
> >> } // namespace
> >>
> >> diff --git a/libsanitizer/tsan/tsan_interceptors_posix.cpp b/libsanitizer/tsan/tsan_interceptors_posix.cpp
> >> index aa04d8dfb67..2651e22c39f 100644
> >> --- a/libsanitizer/tsan/tsan_interceptors_posix.cpp
> >> +++ b/libsanitizer/tsan/tsan_interceptors_posix.cpp
> >> @@ -54,10 +54,6 @@ using namespace __tsan;
> >> #define vfork __vfork14
> >> #endif
> >>
> >> -#if SANITIZER_ANDROID
> >> -#define mallopt(a, b)
> >> -#endif
> >> -
> >> #ifdef __mips__
> >> const int kSigCount = 129;
> >> #else
> >> @@ -85,6 +81,8 @@ extern "C" int pthread_attr_init(void *attr);
> >> extern "C" int pthread_attr_destroy(void *attr);
> >> DECLARE_REAL(int, pthread_attr_getdetachstate, void *, void *)
> >> extern "C" int pthread_attr_setstacksize(void *attr, uptr stacksize);
> >> +extern "C" int pthread_atfork(void (*prepare)(void), void (*parent)(void),
> >> + void (*child)(void));
> >> extern "C" int pthread_key_create(unsigned *key, void (*destructor)(void* v));
> >> extern "C" int pthread_setspecific(unsigned key, const void *v);
> >> DECLARE_REAL(int, pthread_mutexattr_gettype, void *, void *)
> >> @@ -97,7 +95,7 @@ extern "C" void _exit(int status);
> >> extern "C" int fileno_unlocked(void *stream);
> >> extern "C" int dirfd(void *dirp);
> >> #endif
> >> -#if !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_NETBSD
> >> +#if SANITIZER_GLIBC
> >> extern "C" int mallopt(int param, int value);
> >> #endif
> >> #if SANITIZER_NETBSD
> >> @@ -659,8 +657,11 @@ TSAN_INTERCEPTOR(void*, malloc, uptr size) {
> >> return p;
> >> }
> >>
> >> +// In glibc<2.25, dynamic TLS blocks are allocated by __libc_memalign. Intercept
> >> +// __libc_memalign so that (1) we can detect races (2) free will not be called
> >> +// on libc internally allocated blocks.
> >> TSAN_INTERCEPTOR(void*, __libc_memalign, uptr align, uptr sz) {
> >> - SCOPED_TSAN_INTERCEPTOR(__libc_memalign, align, sz);
> >> + SCOPED_INTERCEPTOR_RAW(__libc_memalign, align, sz);
> >> return user_memalign(thr, pc, align, sz);
> >> }
> >>
> >> @@ -773,6 +774,11 @@ static void *mmap_interceptor(ThreadState *thr, uptr pc, Mmap real_mmap,
> >> if (!fix_mmap_addr(&addr, sz, flags)) return MAP_FAILED;
> >> void *res = real_mmap(addr, sz, prot, flags, fd, off);
> >> if (res != MAP_FAILED) {
> >> + if (!IsAppMem((uptr)res) || !IsAppMem((uptr)res + sz - 1)) {
> >> + Report("ThreadSanitizer: mmap at bad address: addr=%p size=%p res=%p\n",
> >> + addr, (void*)sz, res);
> >> + Die();
> >> + }
> >> if (fd > 0) FdAccess(thr, pc, fd);
> >> MemoryRangeImitateWriteOrResetRange(thr, pc, (uptr)res, sz);
> >> }
> >> @@ -1122,27 +1128,37 @@ static void *init_cond(void *c, bool force = false) {
> >> return (void*)cond;
> >> }
> >>
> >> +namespace {
> >> +
> >> +template <class Fn>
> >> struct CondMutexUnlockCtx {
> >> ScopedInterceptor *si;
> >> ThreadState *thr;
> >> uptr pc;
> >> void *m;
> >> + void *c;
> >> + const Fn &fn;
> >> +
> >> + int Cancel() const { return fn(); }
> >> + void Unlock() const;
> >> };
> >>
> >> -static void cond_mutex_unlock(CondMutexUnlockCtx *arg) {
> >> +template <class Fn>
> >> +void CondMutexUnlockCtx<Fn>::Unlock() const {
> >> // pthread_cond_wait interceptor has enabled async signal delivery
> >> // (see BlockingCall below). Disable async signals since we are running
> >> // tsan code. Also ScopedInterceptor and BlockingCall destructors won't run
> >> // since the thread is cancelled, so we have to manually execute them
> >> // (the thread still can run some user code due to pthread_cleanup_push).
> >> - ThreadSignalContext *ctx = SigCtx(arg->thr);
> >> + ThreadSignalContext *ctx = SigCtx(thr);
> >> CHECK_EQ(atomic_load(&ctx->in_blocking_func, memory_order_relaxed), 1);
> >> atomic_store(&ctx->in_blocking_func, 0, memory_order_relaxed);
> >> - MutexPostLock(arg->thr, arg->pc, (uptr)arg->m, MutexFlagDoPreLockOnPostLock);
> >> + MutexPostLock(thr, pc, (uptr)m, MutexFlagDoPreLockOnPostLock);
> >> // Undo BlockingCall ctor effects.
> >> - arg->thr->ignore_interceptors--;
> >> - arg->si->~ScopedInterceptor();
> >> + thr->ignore_interceptors--;
> >> + si->~ScopedInterceptor();
> >> }
> >> +} // namespace
> >>
> >> INTERCEPTOR(int, pthread_cond_init, void *c, void *a) {
> >> void *cond = init_cond(c, true);
> >> @@ -1151,20 +1167,24 @@ INTERCEPTOR(int, pthread_cond_init, void *c, void *a) {
> >> return REAL(pthread_cond_init)(cond, a);
> >> }
> >>
> >> -static int cond_wait(ThreadState *thr, uptr pc, ScopedInterceptor *si,
> >> - int (*fn)(void *c, void *m, void *abstime), void *c,
> >> - void *m, void *t) {
> >> +template <class Fn>
> >> +int cond_wait(ThreadState *thr, uptr pc, ScopedInterceptor *si, const Fn &fn,
> >> + void *c, void *m) {
> >> MemoryAccessRange(thr, pc, (uptr)c, sizeof(uptr), false);
> >> MutexUnlock(thr, pc, (uptr)m);
> >> - CondMutexUnlockCtx arg = {si, thr, pc, m};
> >> int res = 0;
> >> // This ensures that we handle mutex lock even in case of pthread_cancel.
> >> // See test/tsan/cond_cancel.cpp.
> >> {
> >> // Enable signal delivery while the thread is blocked.
> >> BlockingCall bc(thr);
> >> + CondMutexUnlockCtx<Fn> arg = {si, thr, pc, m, c, fn};
> >> res = call_pthread_cancel_with_cleanup(
> >> - fn, c, m, t, (void (*)(void *arg))cond_mutex_unlock, &arg);
> >> + [](void *arg) -> int {
> >> + return ((const CondMutexUnlockCtx<Fn> *)arg)->Cancel();
> >> + },
> >> + [](void *arg) { ((const CondMutexUnlockCtx<Fn> *)arg)->Unlock(); },
> >> + &arg);
> >> }
> >> if (res == errno_EOWNERDEAD) MutexRepair(thr, pc, (uptr)m);
> >> MutexPostLock(thr, pc, (uptr)m, MutexFlagDoPreLockOnPostLock);
> >> @@ -1174,25 +1194,46 @@ static int cond_wait(ThreadState *thr, uptr pc, ScopedInterceptor *si,
> >> INTERCEPTOR(int, pthread_cond_wait, void *c, void *m) {
> >> void *cond = init_cond(c);
> >> SCOPED_TSAN_INTERCEPTOR(pthread_cond_wait, cond, m);
> >> - return cond_wait(thr, pc, &si, (int (*)(void *c, void *m, void *abstime))REAL(
> >> - pthread_cond_wait),
> >> - cond, m, 0);
> >> + return cond_wait(
> >> + thr, pc, &si, [=]() { return REAL(pthread_cond_wait)(cond, m); }, cond,
> >> + m);
> >> }
> >>
> >> INTERCEPTOR(int, pthread_cond_timedwait, void *c, void *m, void *abstime) {
> >> void *cond = init_cond(c);
> >> SCOPED_TSAN_INTERCEPTOR(pthread_cond_timedwait, cond, m, abstime);
> >> - return cond_wait(thr, pc, &si, REAL(pthread_cond_timedwait), cond, m,
> >> - abstime);
> >> + return cond_wait(
> >> + thr, pc, &si,
> >> + [=]() { return REAL(pthread_cond_timedwait)(cond, m, abstime); }, cond,
> >> + m);
> >> }
> >>
> >> +#if SANITIZER_LINUX
> >> +INTERCEPTOR(int, pthread_cond_clockwait, void *c, void *m,
> >> + __sanitizer_clockid_t clock, void *abstime) {
> >> + void *cond = init_cond(c);
> >> + SCOPED_TSAN_INTERCEPTOR(pthread_cond_clockwait, cond, m, clock, abstime);
> >> + return cond_wait(
> >> + thr, pc, &si,
> >> + [=]() { return REAL(pthread_cond_clockwait)(cond, m, clock, abstime); },
> >> + cond, m);
> >> +}
> >> +#define TSAN_MAYBE_PTHREAD_COND_CLOCKWAIT TSAN_INTERCEPT(pthread_cond_clockwait)
> >> +#else
> >> +#define TSAN_MAYBE_PTHREAD_COND_CLOCKWAIT
> >> +#endif
> >> +
> >> #if SANITIZER_MAC
> >> INTERCEPTOR(int, pthread_cond_timedwait_relative_np, void *c, void *m,
> >> void *reltime) {
> >> void *cond = init_cond(c);
> >> SCOPED_TSAN_INTERCEPTOR(pthread_cond_timedwait_relative_np, cond, m, reltime);
> >> - return cond_wait(thr, pc, &si, REAL(pthread_cond_timedwait_relative_np), cond,
> >> - m, reltime);
> >> + return cond_wait(
> >> + thr, pc, &si,
> >> + [=]() {
> >> + return REAL(pthread_cond_timedwait_relative_np)(cond, m, reltime);
> >> + },
> >> + cond, m);
> >> }
> >> #endif
> >>
> >> @@ -1937,7 +1978,8 @@ static void CallUserSignalHandler(ThreadState *thr, bool sync, bool acquire,
> >> // because in async signal processing case (when handler is called directly
> >> // from rtl_generic_sighandler) we have not yet received the reraised
> >> // signal; and it looks too fragile to intercept all ways to reraise a signal.
> >> - if (flags()->report_bugs && !sync && sig != SIGTERM && errno != 99) {
> >> + if (ShouldReport(thr, ReportTypeErrnoInSignal) && !sync && sig != SIGTERM &&
> >> + errno != 99) {
> >> VarSizeStackTrace stack;
> >> // StackTrace::GetNestInstructionPc(pc) is used because return address is
> >> // expected, OutputReport() will undo this.
> >> @@ -2107,26 +2149,32 @@ TSAN_INTERCEPTOR(int, fork, int fake) {
> >> if (in_symbolizer())
> >> return REAL(fork)(fake);
> >> SCOPED_INTERCEPTOR_RAW(fork, fake);
> >> + return REAL(fork)(fake);
> >> +}
> >> +
> >> +void atfork_prepare() {
> >> + if (in_symbolizer())
> >> + return;
> >> + ThreadState *thr = cur_thread();
> >> + const uptr pc = StackTrace::GetCurrentPc();
> >> ForkBefore(thr, pc);
> >> - int pid;
> >> - {
> >> - // On OS X, REAL(fork) can call intercepted functions (OSSpinLockLock), and
> >> - // we'll assert in CheckNoLocks() unless we ignore interceptors.
> >> - ScopedIgnoreInterceptors ignore;
> >> - pid = REAL(fork)(fake);
> >> - }
> >> - if (pid == 0) {
> >> - // child
> >> - ForkChildAfter(thr, pc);
> >> - FdOnFork(thr, pc);
> >> - } else if (pid > 0) {
> >> - // parent
> >> - ForkParentAfter(thr, pc);
> >> - } else {
> >> - // error
> >> - ForkParentAfter(thr, pc);
> >> - }
> >> - return pid;
> >> +}
> >> +
> >> +void atfork_parent() {
> >> + if (in_symbolizer())
> >> + return;
> >> + ThreadState *thr = cur_thread();
> >> + const uptr pc = StackTrace::GetCurrentPc();
> >> + ForkParentAfter(thr, pc);
> >> +}
> >> +
> >> +void atfork_child() {
> >> + if (in_symbolizer())
> >> + return;
> >> + ThreadState *thr = cur_thread();
> >> + const uptr pc = StackTrace::GetCurrentPc();
> >> + ForkChildAfter(thr, pc);
> >> + FdOnFork(thr, pc);
> >> }
> >>
> >> TSAN_INTERCEPTOR(int, vfork, int fake) {
> >> @@ -2479,13 +2527,10 @@ static USED void syscall_fd_release(uptr pc, int fd) {
> >> FdRelease(thr, pc, fd);
> >> }
> >>
> >> -static void syscall_pre_fork(uptr pc) {
> >> - TSAN_SYSCALL();
> >> - ForkBefore(thr, pc);
> >> -}
> >> +static void syscall_pre_fork(uptr pc) { ForkBefore(cur_thread(), pc); }
> >>
> >> static void syscall_post_fork(uptr pc, int pid) {
> >> - TSAN_SYSCALL();
> >> + ThreadState *thr = cur_thread();
> >> if (pid == 0) {
> >> // child
> >> ForkChildAfter(thr, pc);
> >> @@ -2635,7 +2680,7 @@ void InitializeInterceptors() {
> >> #endif
> >>
> >> // Instruct libc malloc to consume less memory.
> >> -#if SANITIZER_LINUX
> >> +#if SANITIZER_GLIBC
> >> mallopt(1, 0); // M_MXFAST
> >> mallopt(-3, 32*1024); // M_MMAP_THRESHOLD
> >> #endif
> >> @@ -2698,6 +2743,8 @@ void InitializeInterceptors() {
> >> TSAN_INTERCEPT_VER(pthread_cond_timedwait, PTHREAD_ABI_BASE);
> >> TSAN_INTERCEPT_VER(pthread_cond_destroy, PTHREAD_ABI_BASE);
> >>
> >> + TSAN_MAYBE_PTHREAD_COND_CLOCKWAIT;
> >> +
> >> TSAN_INTERCEPT(pthread_mutex_init);
> >> TSAN_INTERCEPT(pthread_mutex_destroy);
> >> TSAN_INTERCEPT(pthread_mutex_trylock);
> >> @@ -2799,6 +2846,10 @@ void InitializeInterceptors() {
> >> Printf("ThreadSanitizer: failed to setup atexit callback\n");
> >> Die();
> >> }
> >> + if (pthread_atfork(atfork_prepare, atfork_parent, atfork_child)) {
> >> + Printf("ThreadSanitizer: failed to setup atfork callbacks\n");
> >> + Die();
> >> + }
> >>
> >> #if !SANITIZER_MAC && !SANITIZER_NETBSD && !SANITIZER_FREEBSD
> >> if (pthread_key_create(&interceptor_ctx()->finalize_key, &thread_finalize)) {
> >> diff --git a/libsanitizer/tsan/tsan_interface.cpp b/libsanitizer/tsan/tsan_interface.cpp
> >> index 55f1c9834f7..9bd0e8580b1 100644
> >> --- a/libsanitizer/tsan/tsan_interface.cpp
> >> +++ b/libsanitizer/tsan/tsan_interface.cpp
> >> @@ -40,13 +40,13 @@ void __tsan_write16(void *addr) {
> >> }
> >>
> >> void __tsan_read16_pc(void *addr, void *pc) {
> >> - MemoryRead(cur_thread(), STRIP_PC(pc), (uptr)addr, kSizeLog8);
> >> - MemoryRead(cur_thread(), STRIP_PC(pc), (uptr)addr + 8, kSizeLog8);
> >> + MemoryRead(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, kSizeLog8);
> >> + MemoryRead(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr + 8, kSizeLog8);
> >> }
> >>
> >> void __tsan_write16_pc(void *addr, void *pc) {
> >> - MemoryWrite(cur_thread(), STRIP_PC(pc), (uptr)addr, kSizeLog8);
> >> - MemoryWrite(cur_thread(), STRIP_PC(pc), (uptr)addr + 8, kSizeLog8);
> >> + MemoryWrite(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, kSizeLog8);
> >> + MemoryWrite(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr + 8, kSizeLog8);
> >> }
> >>
> >> // __tsan_unaligned_read/write calls are emitted by compiler.
> >> diff --git a/libsanitizer/tsan/tsan_interface.h b/libsanitizer/tsan/tsan_interface.h
> >> index 6d7286ca5b8..6e022b56850 100644
> >> --- a/libsanitizer/tsan/tsan_interface.h
> >> +++ b/libsanitizer/tsan/tsan_interface.h
> >> @@ -204,7 +204,7 @@ __extension__ typedef __int128 a128;
> >> #endif
> >>
> >> // Part of ABI, do not change.
> >> -// https://github.com/llvm/llvm-project/blob/master/libcxx/include/atomic
> >> +// https://github.com/llvm/llvm-project/blob/main/libcxx/include/atomic
> >> typedef enum {
> >> mo_relaxed,
> >> mo_consume,
> >> @@ -415,6 +415,13 @@ void __tsan_go_atomic32_compare_exchange(ThreadState *thr, uptr cpc, uptr pc,
> >> SANITIZER_INTERFACE_ATTRIBUTE
> >> void __tsan_go_atomic64_compare_exchange(ThreadState *thr, uptr cpc, uptr pc,
> >> u8 *a);
> >> +
> >> +SANITIZER_INTERFACE_ATTRIBUTE
> >> +void __tsan_on_initialize();
> >> +
> >> +SANITIZER_INTERFACE_ATTRIBUTE
> >> +int __tsan_on_finalize(int failed);
> >> +
> >> } // extern "C"
> >>
> >> } // namespace __tsan
> >> diff --git a/libsanitizer/tsan/tsan_interface_inl.h b/libsanitizer/tsan/tsan_interface_inl.h
> >> index f5d743c1077..5e77d4d3d28 100644
> >> --- a/libsanitizer/tsan/tsan_interface_inl.h
> >> +++ b/libsanitizer/tsan/tsan_interface_inl.h
> >> @@ -51,35 +51,35 @@ void __tsan_write8(void *addr) {
> >> }
> >>
> >> void __tsan_read1_pc(void *addr, void *pc) {
> >> - MemoryRead(cur_thread(), STRIP_PC(pc), (uptr)addr, kSizeLog1);
> >> + MemoryRead(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, kSizeLog1);
> >> }
> >>
> >> void __tsan_read2_pc(void *addr, void *pc) {
> >> - MemoryRead(cur_thread(), STRIP_PC(pc), (uptr)addr, kSizeLog2);
> >> + MemoryRead(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, kSizeLog2);
> >> }
> >>
> >> void __tsan_read4_pc(void *addr, void *pc) {
> >> - MemoryRead(cur_thread(), STRIP_PC(pc), (uptr)addr, kSizeLog4);
> >> + MemoryRead(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, kSizeLog4);
> >> }
> >>
> >> void __tsan_read8_pc(void *addr, void *pc) {
> >> - MemoryRead(cur_thread(), STRIP_PC(pc), (uptr)addr, kSizeLog8);
> >> + MemoryRead(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, kSizeLog8);
> >> }
> >>
> >> void __tsan_write1_pc(void *addr, void *pc) {
> >> - MemoryWrite(cur_thread(), STRIP_PC(pc), (uptr)addr, kSizeLog1);
> >> + MemoryWrite(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, kSizeLog1);
> >> }
> >>
> >> void __tsan_write2_pc(void *addr, void *pc) {
> >> - MemoryWrite(cur_thread(), STRIP_PC(pc), (uptr)addr, kSizeLog2);
> >> + MemoryWrite(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, kSizeLog2);
> >> }
> >>
> >> void __tsan_write4_pc(void *addr, void *pc) {
> >> - MemoryWrite(cur_thread(), STRIP_PC(pc), (uptr)addr, kSizeLog4);
> >> + MemoryWrite(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, kSizeLog4);
> >> }
> >>
> >> void __tsan_write8_pc(void *addr, void *pc) {
> >> - MemoryWrite(cur_thread(), STRIP_PC(pc), (uptr)addr, kSizeLog8);
> >> + MemoryWrite(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, kSizeLog8);
> >> }
> >>
> >> void __tsan_vptr_update(void **vptr_p, void *new_val) {
> >> @@ -101,7 +101,7 @@ void __tsan_vptr_read(void **vptr_p) {
> >> }
> >>
> >> void __tsan_func_entry(void *pc) {
> >> - FuncEntry(cur_thread(), STRIP_PC(pc));
> >> + FuncEntry(cur_thread(), STRIP_PAC_PC(pc));
> >> }
> >>
> >> void __tsan_func_exit() {
> >> @@ -125,9 +125,9 @@ void __tsan_write_range(void *addr, uptr size) {
> >> }
> >>
> >> void __tsan_read_range_pc(void *addr, uptr size, void *pc) {
> >> - MemoryAccessRange(cur_thread(), STRIP_PC(pc), (uptr)addr, size, false);
> >> + MemoryAccessRange(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, size, false);
> >> }
> >>
> >> void __tsan_write_range_pc(void *addr, uptr size, void *pc) {
> >> - MemoryAccessRange(cur_thread(), STRIP_PC(pc), (uptr)addr, size, true);
> >> + MemoryAccessRange(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, size, true);
> >> }
> >> diff --git a/libsanitizer/tsan/tsan_mman.cpp b/libsanitizer/tsan/tsan_mman.cpp
> >> index 743e67bf2f7..45a39f0f8ec 100644
> >> --- a/libsanitizer/tsan/tsan_mman.cpp
> >> +++ b/libsanitizer/tsan/tsan_mman.cpp
> >> @@ -145,7 +145,7 @@ void AllocatorPrintStats() {
> >>
> >> static void SignalUnsafeCall(ThreadState *thr, uptr pc) {
> >> if (atomic_load_relaxed(&thr->in_signal_handler) == 0 ||
> >> - !flags()->report_signal_unsafe)
> >> + !ShouldReport(thr, ReportTypeSignalUnsafe))
> >> return;
> >> VarSizeStackTrace stack;
> >> ObtainCurrentStack(thr, pc, &stack);
> >> diff --git a/libsanitizer/tsan/tsan_platform.h b/libsanitizer/tsan/tsan_platform.h
> >> index 16169cab666..101522d8fa4 100644
> >> --- a/libsanitizer/tsan/tsan_platform.h
> >> +++ b/libsanitizer/tsan/tsan_platform.h
> >> @@ -23,9 +23,21 @@
> >>
> >> namespace __tsan {
> >>
> >> +#if defined(__x86_64__)
> >> +#define HAS_48_BIT_ADDRESS_SPACE 1
> >> +#elif SANITIZER_IOSSIM // arm64 iOS simulators (order of #if matters)
> >> +#define HAS_48_BIT_ADDRESS_SPACE 1
> >> +#elif SANITIZER_IOS // arm64 iOS devices (order of #if matters)
> >> +#define HAS_48_BIT_ADDRESS_SPACE 0
> >> +#elif SANITIZER_MAC // arm64 macOS (order of #if matters)
> >> +#define HAS_48_BIT_ADDRESS_SPACE 1
> >> +#else
> >> +#define HAS_48_BIT_ADDRESS_SPACE 0
> >> +#endif
> >> +
> >> #if !SANITIZER_GO
> >>
> >> -#if defined(__x86_64__)
> >> +#if HAS_48_BIT_ADDRESS_SPACE
> >> /*
> >> C/C++ on linux/x86_64 and freebsd/x86_64
> >> 0000 0000 1000 - 0080 0000 0000: main binary and/or MAP_32BIT mappings (512GB)
> >> @@ -93,7 +105,7 @@ fe00 0000 00 - ff00 0000 00: heap (4 GB)
> >> ff00 0000 00 - ff80 0000 00: - (2 GB)
> >> ff80 0000 00 - ffff ffff ff: modules and main thread stack (<2 GB)
> >> */
> >> -struct Mapping {
> >> +struct Mapping40 {
> >> static const uptr kMetaShadowBeg = 0x4000000000ull;
> >> static const uptr kMetaShadowEnd = 0x5000000000ull;
> >> static const uptr kTraceMemBeg = 0xb000000000ull;
> >> @@ -114,6 +126,7 @@ struct Mapping {
> >> };
> >>
> >> #define TSAN_MID_APP_RANGE 1
> >> +#define TSAN_RUNTIME_VMA 1
> >> #elif defined(__aarch64__) && defined(__APPLE__)
> >> /*
> >> C/C++ on Darwin/iOS/ARM64 (36-bit VMA, 64 GB VM)
> >> @@ -146,7 +159,7 @@ struct Mapping {
> >> static const uptr kVdsoBeg = 0x7000000000000000ull;
> >> };
> >>
> >> -#elif defined(__aarch64__)
> >> +#elif defined(__aarch64__) && !defined(__APPLE__)
> >> // AArch64 supports multiple VMA which leads to multiple address transformation
> >> // functions. To support these multiple VMAS transformations and mappings TSAN
> >> // runtime for AArch64 uses an external memory read (vmaSize) to select which
> >> @@ -354,7 +367,7 @@ struct Mapping47 {
> >> #define TSAN_RUNTIME_VMA 1
> >> #endif
> >>
> >> -#elif SANITIZER_GO && !SANITIZER_WINDOWS && defined(__x86_64__)
> >> +#elif SANITIZER_GO && !SANITIZER_WINDOWS && HAS_48_BIT_ADDRESS_SPACE
> >>
> >> /* Go on linux, darwin and freebsd on x86_64
> >> 0000 0000 1000 - 0000 1000 0000: executable
> >> @@ -502,7 +515,7 @@ Go on linux/mips64 (47-bit VMA)
> >> 6000 0000 0000 - 6200 0000 0000: traces
> >> 6200 0000 0000 - 8000 0000 0000: -
> >> */
> >> -struct Mapping {
> >> +struct Mapping47 {
> >> static const uptr kMetaShadowBeg = 0x300000000000ull;
> >> static const uptr kMetaShadowEnd = 0x400000000000ull;
> >> static const uptr kTraceMemBeg = 0x600000000000ull;
> >> @@ -512,6 +525,9 @@ struct Mapping {
> >> static const uptr kAppMemBeg = 0x000000001000ull;
> >> static const uptr kAppMemEnd = 0x00e000000000ull;
> >> };
> >> +
> >> +#define TSAN_RUNTIME_VMA 1
> >> +
> >> #else
> >> # error "Unknown platform"
> >> #endif
> >> @@ -592,6 +608,16 @@ uptr MappingArchImpl(void) {
> >> }
> >> DCHECK(0);
> >> return 0;
> >> +#elif defined(__mips64)
> >> + switch (vmaSize) {
> >> +#if !SANITIZER_GO
> >> + case 40: return MappingImpl<Mapping40, Type>();
> >> +#else
> >> + case 47: return MappingImpl<Mapping47, Type>();
> >> +#endif
> >> + }
> >> + DCHECK(0);
> >> + return 0;
> >> #else
> >> return MappingImpl<Mapping, Type>();
> >> #endif
> >> @@ -749,6 +775,16 @@ bool IsAppMem(uptr mem) {
> >> }
> >> DCHECK(0);
> >> return false;
> >> +#elif defined(__mips64)
> >> + switch (vmaSize) {
> >> +#if !SANITIZER_GO
> >> + case 40: return IsAppMemImpl<Mapping40>(mem);
> >> +#else
> >> + case 47: return IsAppMemImpl<Mapping47>(mem);
> >> +#endif
> >> + }
> >> + DCHECK(0);
> >> + return false;
> >> #else
> >> return IsAppMemImpl<Mapping>(mem);
> >> #endif
> >> @@ -780,6 +816,16 @@ bool IsShadowMem(uptr mem) {
> >> }
> >> DCHECK(0);
> >> return false;
> >> +#elif defined(__mips64)
> >> + switch (vmaSize) {
> >> +#if !SANITIZER_GO
> >> + case 40: return IsShadowMemImpl<Mapping40>(mem);
> >> +#else
> >> + case 47: return IsShadowMemImpl<Mapping47>(mem);
> >> +#endif
> >> + }
> >> + DCHECK(0);
> >> + return false;
> >> #else
> >> return IsShadowMemImpl<Mapping>(mem);
> >> #endif
> >> @@ -811,6 +857,16 @@ bool IsMetaMem(uptr mem) {
> >> }
> >> DCHECK(0);
> >> return false;
> >> +#elif defined(__mips64)
> >> + switch (vmaSize) {
> >> +#if !SANITIZER_GO
> >> + case 40: return IsMetaMemImpl<Mapping40>(mem);
> >> +#else
> >> + case 47: return IsMetaMemImpl<Mapping47>(mem);
> >> +#endif
> >> + }
> >> + DCHECK(0);
> >> + return false;
> >> #else
> >> return IsMetaMemImpl<Mapping>(mem);
> >> #endif
> >> @@ -852,6 +908,16 @@ uptr MemToShadow(uptr x) {
> >> }
> >> DCHECK(0);
> >> return 0;
> >> +#elif defined(__mips64)
> >> + switch (vmaSize) {
> >> +#if !SANITIZER_GO
> >> + case 40: return MemToShadowImpl<Mapping40>(x);
> >> +#else
> >> + case 47: return MemToShadowImpl<Mapping47>(x);
> >> +#endif
> >> + }
> >> + DCHECK(0);
> >> + return 0;
> >> #else
> >> return MemToShadowImpl<Mapping>(x);
> >> #endif
> >> @@ -895,6 +961,16 @@ u32 *MemToMeta(uptr x) {
> >> }
> >> DCHECK(0);
> >> return 0;
> >> +#elif defined(__mips64)
> >> + switch (vmaSize) {
> >> +#if !SANITIZER_GO
> >> + case 40: return MemToMetaImpl<Mapping40>(x);
> >> +#else
> >> + case 47: return MemToMetaImpl<Mapping47>(x);
> >> +#endif
> >> + }
> >> + DCHECK(0);
> >> + return 0;
> >> #else
> >> return MemToMetaImpl<Mapping>(x);
> >> #endif
> >> @@ -951,6 +1027,16 @@ uptr ShadowToMem(uptr s) {
> >> }
> >> DCHECK(0);
> >> return 0;
> >> +#elif defined(__mips64)
> >> + switch (vmaSize) {
> >> +#if !SANITIZER_GO
> >> + case 40: return ShadowToMemImpl<Mapping40>(s);
> >> +#else
> >> + case 47: return ShadowToMemImpl<Mapping47>(s);
> >> +#endif
> >> + }
> >> + DCHECK(0);
> >> + return 0;
> >> #else
> >> return ShadowToMemImpl<Mapping>(s);
> >> #endif
> >> @@ -990,6 +1076,16 @@ uptr GetThreadTrace(int tid) {
> >> }
> >> DCHECK(0);
> >> return 0;
> >> +#elif defined(__mips64)
> >> + switch (vmaSize) {
> >> +#if !SANITIZER_GO
> >> + case 40: return GetThreadTraceImpl<Mapping40>(tid);
> >> +#else
> >> + case 47: return GetThreadTraceImpl<Mapping47>(tid);
> >> +#endif
> >> + }
> >> + DCHECK(0);
> >> + return 0;
> >> #else
> >> return GetThreadTraceImpl<Mapping>(tid);
> >> #endif
> >> @@ -1024,6 +1120,16 @@ uptr GetThreadTraceHeader(int tid) {
> >> }
> >> DCHECK(0);
> >> return 0;
> >> +#elif defined(__mips64)
> >> + switch (vmaSize) {
> >> +#if !SANITIZER_GO
> >> + case 40: return GetThreadTraceHeaderImpl<Mapping40>(tid);
> >> +#else
> >> + case 47: return GetThreadTraceHeaderImpl<Mapping47>(tid);
> >> +#endif
> >> + }
> >> + DCHECK(0);
> >> + return 0;
> >> #else
> >> return GetThreadTraceHeaderImpl<Mapping>(tid);
> >> #endif
> >> @@ -1040,9 +1146,8 @@ int ExtractRecvmsgFDs(void *msg, int *fds, int nfd);
> >> uptr ExtractLongJmpSp(uptr *env);
> >> void ImitateTlsWrite(ThreadState *thr, uptr tls_addr, uptr tls_size);
> >>
> >> -int call_pthread_cancel_with_cleanup(int(*fn)(void *c, void *m,
> >> - void *abstime), void *c, void *m, void *abstime,
> >> - void(*cleanup)(void *arg), void *arg);
> >> +int call_pthread_cancel_with_cleanup(int (*fn)(void *arg),
> >> + void (*cleanup)(void *arg), void *arg);
> >>
> >> void DestroyThreadState();
> >> void PlatformCleanUpThreadState(ThreadState *thr);
> >> diff --git a/libsanitizer/tsan/tsan_platform_linux.cpp b/libsanitizer/tsan/tsan_platform_linux.cpp
> >> index d136dcb1cec..e5b6690edfd 100644
> >> --- a/libsanitizer/tsan/tsan_platform_linux.cpp
> >> +++ b/libsanitizer/tsan/tsan_platform_linux.cpp
> >> @@ -250,6 +250,20 @@ void InitializePlatformEarly() {
> >> Die();
> >> }
> >> # endif
> >> +#elif defined(__mips64)
> >> +# if !SANITIZER_GO
> >> + if (vmaSize != 40) {
> >> + Printf("FATAL: ThreadSanitizer: unsupported VMA range\n");
> >> + Printf("FATAL: Found %zd - Supported 40\n", vmaSize);
> >> + Die();
> >> + }
> >> +# else
> >> + if (vmaSize != 47) {
> >> + Printf("FATAL: ThreadSanitizer: unsupported VMA range\n");
> >> + Printf("FATAL: Found %zd - Supported 47\n", vmaSize);
> >> + Die();
> >> + }
> >> +# endif
> >> #endif
> >> #endif
> >> }
> >> @@ -443,14 +457,13 @@ void ImitateTlsWrite(ThreadState *thr, uptr tls_addr, uptr tls_size) {
> >>
> >> // Note: this function runs with async signals enabled,
> >> // so it must not touch any tsan state.
> >> -int call_pthread_cancel_with_cleanup(int(*fn)(void *c, void *m,
> >> - void *abstime), void *c, void *m, void *abstime,
> >> - void(*cleanup)(void *arg), void *arg) {
> >> +int call_pthread_cancel_with_cleanup(int (*fn)(void *arg),
> >> + void (*cleanup)(void *arg), void *arg) {
> >> // pthread_cleanup_push/pop are hardcore macros mess.
> >> // We can't intercept nor call them w/o including pthread.h.
> >> int res;
> >> pthread_cleanup_push(cleanup, arg);
> >> - res = fn(c, m, abstime);
> >> + res = fn(arg);
> >> pthread_cleanup_pop(0);
> >> return res;
> >> }
> >> @@ -484,7 +497,7 @@ ThreadState *cur_thread() {
> >> dead_thread_state->fast_state.SetIgnoreBit();
> >> dead_thread_state->ignore_interceptors = 1;
> >> dead_thread_state->is_dead = true;
> >> - *const_cast<int*>(&dead_thread_state->tid) = -1;
> >> + *const_cast<u32*>(&dead_thread_state->tid) = -1;
> >> CHECK_EQ(0, internal_mprotect(dead_thread_state, sizeof(ThreadState),
> >> PROT_READ));
> >> }
> >> diff --git a/libsanitizer/tsan/tsan_platform_mac.cpp b/libsanitizer/tsan/tsan_platform_mac.cpp
> >> index ec2c5fb1621..d9719a136b2 100644
> >> --- a/libsanitizer/tsan/tsan_platform_mac.cpp
> >> +++ b/libsanitizer/tsan/tsan_platform_mac.cpp
> >> @@ -234,7 +234,7 @@ static void my_pthread_introspection_hook(unsigned int event, pthread_t thread,
> >> #endif
> >>
> >> void InitializePlatformEarly() {
> >> -#if !SANITIZER_GO && defined(__aarch64__)
> >> +#if !SANITIZER_GO && !HAS_48_BIT_ADDRESS_SPACE
> >> uptr max_vm = GetMaxUserVirtualAddress() + 1;
> >> if (max_vm != Mapping::kHiAppMemEnd) {
> >> Printf("ThreadSanitizer: unsupported vm address limit %p, expected %p.\n",
> >> @@ -306,14 +306,13 @@ void ImitateTlsWrite(ThreadState *thr, uptr tls_addr, uptr tls_size) {
> >> #if !SANITIZER_GO
> >> // Note: this function runs with async signals enabled,
> >> // so it must not touch any tsan state.
> >> -int call_pthread_cancel_with_cleanup(int(*fn)(void *c, void *m,
> >> - void *abstime), void *c, void *m, void *abstime,
> >> - void(*cleanup)(void *arg), void *arg) {
> >> +int call_pthread_cancel_with_cleanup(int (*fn)(void *arg),
> >> + void (*cleanup)(void *arg), void *arg) {
> >> // pthread_cleanup_push/pop are hardcore macros mess.
> >> // We can't intercept nor call them w/o including pthread.h.
> >> int res;
> >> pthread_cleanup_push(cleanup, arg);
> >> - res = fn(c, m, abstime);
> >> + res = fn(arg);
> >> pthread_cleanup_pop(0);
> >> return res;
> >> }
> >> diff --git a/libsanitizer/tsan/tsan_platform_posix.cpp b/libsanitizer/tsan/tsan_platform_posix.cpp
> >> index d56b6c3b9c5..73e1d4577c2 100644
> >> --- a/libsanitizer/tsan/tsan_platform_posix.cpp
> >> +++ b/libsanitizer/tsan/tsan_platform_posix.cpp
> >> @@ -99,7 +99,7 @@ void CheckAndProtect() {
> >> Die();
> >> }
> >>
> >> -#if defined(__aarch64__) && defined(__APPLE__)
> >> +#if defined(__aarch64__) && defined(__APPLE__) && !HAS_48_BIT_ADDRESS_SPACE
> >> ProtectRange(HeapMemEnd(), ShadowBeg());
> >> ProtectRange(ShadowEnd(), MetaShadowBeg());
> >> ProtectRange(MetaShadowEnd(), TraceMemBeg());
> >> diff --git a/libsanitizer/tsan/tsan_report.cpp b/libsanitizer/tsan/tsan_report.cpp
> >> index 968c7b97553..8ef9f0cd4fe 100644
> >> --- a/libsanitizer/tsan/tsan_report.cpp
> >> +++ b/libsanitizer/tsan/tsan_report.cpp
> >> @@ -69,7 +69,7 @@ ReportDesc::~ReportDesc() {
> >>
> >> const int kThreadBufSize = 32;
> >> const char *thread_name(char *buf, int tid) {
> >> - if (tid == 0)
> >> + if (tid == kMainTid)
> >> return "main thread";
> >> internal_snprintf(buf, kThreadBufSize, "thread T%d", tid);
> >> return buf;
> >> @@ -127,7 +127,7 @@ void PrintStack(const ReportStack *ent) {
> >> }
> >> SymbolizedStack *frame = ent->frames;
> >> for (int i = 0; frame && frame->info.address; frame = frame->next, i++) {
> >> - InternalScopedString res(2 * GetPageSizeCached());
> >> + InternalScopedString res;
> >> RenderFrame(&res, common_flags()->stack_trace_format, i,
> >> frame->info.address, &frame->info,
> >> common_flags()->symbolize_vs_style,
> >> @@ -250,7 +250,7 @@ static void PrintMutex(const ReportMutex *rm) {
> >>
> >> static void PrintThread(const ReportThread *rt) {
> >> Decorator d;
> >> - if (rt->id == 0) // Little sense in describing the main thread.
> >> + if (rt->id == kMainTid) // Little sense in describing the main thread.
> >> return;
> >> Printf("%s", d.ThreadDescription());
> >> Printf(" Thread T%d", rt->id);
> >> @@ -394,7 +394,7 @@ void PrintReport(const ReportDesc *rep) {
> >>
> >> #else // #if !SANITIZER_GO
> >>
> >> -const int kMainThreadId = 1;
> >> +const u32 kMainGoroutineId = 1;
> >>
> >> void PrintStack(const ReportStack *ent) {
> >> if (ent == 0 || ent->frames == 0) {
> >> @@ -415,7 +415,7 @@ static void PrintMop(const ReportMop *mop, bool first) {
> >> Printf("%s at %p by ",
> >> (first ? (mop->write ? "Write" : "Read")
> >> : (mop->write ? "Previous write" : "Previous read")), mop->addr);
> >> - if (mop->tid == kMainThreadId)
> >> + if (mop->tid == kMainGoroutineId)
> >> Printf("main goroutine:\n");
> >> else
> >> Printf("goroutine %d:\n", mop->tid);
> >> @@ -428,7 +428,7 @@ static void PrintLocation(const ReportLocation *loc) {
> >> Printf("\n");
> >> Printf("Heap block of size %zu at %p allocated by ",
> >> loc->heap_chunk_size, loc->heap_chunk_start);
> >> - if (loc->tid == kMainThreadId)
> >> + if (loc->tid == kMainGoroutineId)
> >> Printf("main goroutine:\n");
> >> else
> >> Printf("goroutine %d:\n", loc->tid);
> >> @@ -448,7 +448,7 @@ static void PrintLocation(const ReportLocation *loc) {
> >> }
> >>
> >> static void PrintThread(const ReportThread *rt) {
> >> - if (rt->id == kMainThreadId)
> >> + if (rt->id == kMainGoroutineId)
> >> return;
> >> Printf("\n");
> >> Printf("Goroutine %d (%s) created at:\n",
> >> diff --git a/libsanitizer/tsan/tsan_rtl.cpp b/libsanitizer/tsan/tsan_rtl.cpp
> >> index 3d721eb95a2..0efa99788ab 100644
> >> --- a/libsanitizer/tsan/tsan_rtl.cpp
> >> +++ b/libsanitizer/tsan/tsan_rtl.cpp
> >> @@ -11,17 +11,19 @@
> >> // Main file (entry points) for the TSan run-time.
> >> //===----------------------------------------------------------------------===//
> >>
> >> +#include "tsan_rtl.h"
> >> +
> >> #include "sanitizer_common/sanitizer_atomic.h"
> >> #include "sanitizer_common/sanitizer_common.h"
> >> #include "sanitizer_common/sanitizer_file.h"
> >> #include "sanitizer_common/sanitizer_libc.h"
> >> -#include "sanitizer_common/sanitizer_stackdepot.h"
> >> #include "sanitizer_common/sanitizer_placement_new.h"
> >> +#include "sanitizer_common/sanitizer_stackdepot.h"
> >> #include "sanitizer_common/sanitizer_symbolizer.h"
> >> #include "tsan_defs.h"
> >> -#include "tsan_platform.h"
> >> -#include "tsan_rtl.h"
> >> +#include "tsan_interface.h"
> >> #include "tsan_mman.h"
> >> +#include "tsan_platform.h"
> >> #include "tsan_suppressions.h"
> >> #include "tsan_symbolize.h"
> >> #include "ubsan/ubsan_init.h"
> >> @@ -56,12 +58,23 @@ Context *ctx;
> >> bool OnFinalize(bool failed);
> >> void OnInitialize();
> >> #else
> >> +#include <dlfcn.h>
> >> SANITIZER_WEAK_CXX_DEFAULT_IMPL
> >> bool OnFinalize(bool failed) {
> >> +#if !SANITIZER_GO
> >> + if (auto *ptr = dlsym(RTLD_DEFAULT, "__tsan_on_finalize"))
> >> + return reinterpret_cast<decltype(&__tsan_on_finalize)>(ptr)(failed);
> >> +#endif
> >> return failed;
> >> }
> >> SANITIZER_WEAK_CXX_DEFAULT_IMPL
> >> -void OnInitialize() {}
> >> +void OnInitialize() {
> >> +#if !SANITIZER_GO
> >> + if (auto *ptr = dlsym(RTLD_DEFAULT, "__tsan_on_initialize")) {
> >> + return reinterpret_cast<decltype(&__tsan_on_initialize)>(ptr)();
> >> + }
> >> +#endif
> >> +}
> >> #endif
> >>
> >> static char thread_registry_placeholder[sizeof(ThreadRegistry)];
> >> @@ -77,12 +90,19 @@ static ThreadContextBase *CreateThreadContext(u32 tid) {
> >> new((void*)hdr) Trace();
> >> // We are going to use only a small part of the trace with the default
> >> // value of history_size. However, the constructor writes to the whole trace.
> >> - // Unmap the unused part.
> >> + // Release the unused part.
> >> uptr hdr_end = hdr + sizeof(Trace);
> >> hdr_end -= sizeof(TraceHeader) * (kTraceParts - TraceParts());
> >> hdr_end = RoundUp(hdr_end, GetPageSizeCached());
> >> - if (hdr_end < hdr + sizeof(Trace))
> >> - UnmapOrDie((void*)hdr_end, hdr + sizeof(Trace) - hdr_end);
> >> + if (hdr_end < hdr + sizeof(Trace)) {
> >> + ReleaseMemoryPagesToOS(hdr_end, hdr + sizeof(Trace));
> >> + uptr unused = hdr + sizeof(Trace) - hdr_end;
> >> + if (hdr_end != (uptr)MmapFixedNoAccess(hdr_end, unused)) {
> >> + Report("ThreadSanitizer: failed to mprotect(%p, %p)\n",
> >> + hdr_end, unused);
> >> + CHECK("unable to mprotect" && 0);
> >> + }
> >> + }
> >> void *mem = internal_alloc(MBlockThreadContex, sizeof(ThreadContext));
> >> return new(mem) ThreadContext(tid);
> >> }
> >> @@ -94,42 +114,45 @@ static const u32 kThreadQuarantineSize = 64;
> >> #endif
> >>
> >> Context::Context()
> >> - : initialized()
> >> - , report_mtx(MutexTypeReport, StatMtxReport)
> >> - , nreported()
> >> - , nmissed_expected()
> >> - , thread_registry(new(thread_registry_placeholder) ThreadRegistry(
> >> - CreateThreadContext, kMaxTid, kThreadQuarantineSize, kMaxTidReuse))
> >> - , racy_mtx(MutexTypeRacy, StatMtxRacy)
> >> - , racy_stacks()
> >> - , racy_addresses()
> >> - , fired_suppressions_mtx(MutexTypeFired, StatMtxFired)
> >> - , clock_alloc("clock allocator") {
> >> + : initialized(),
> >> + report_mtx(MutexTypeReport, StatMtxReport),
> >> + nreported(),
> >> + nmissed_expected(),
> >> + thread_registry(new (thread_registry_placeholder) ThreadRegistry(
> >> + CreateThreadContext, kMaxTid, kThreadQuarantineSize, kMaxTidReuse)),
> >> + racy_mtx(MutexTypeRacy, StatMtxRacy),
> >> + racy_stacks(),
> >> + racy_addresses(),
> >> + fired_suppressions_mtx(MutexTypeFired, StatMtxFired),
> >> + clock_alloc(LINKER_INITIALIZED, "clock allocator") {
> >> fired_suppressions.reserve(8);
> >> }
> >>
> >> // The objects are allocated in TLS, so one may rely on zero-initialization.
> >> -ThreadState::ThreadState(Context *ctx, int tid, int unique_id, u64 epoch,
> >> - unsigned reuse_count,
> >> - uptr stk_addr, uptr stk_size,
> >> +ThreadState::ThreadState(Context *ctx, u32 tid, int unique_id, u64 epoch,
> >> + unsigned reuse_count, uptr stk_addr, uptr stk_size,
> >> uptr tls_addr, uptr tls_size)
> >> - : fast_state(tid, epoch)
> >> - // Do not touch these, rely on zero initialization,
> >> - // they may be accessed before the ctor.
> >> - // , ignore_reads_and_writes()
> >> - // , ignore_interceptors()
> >> - , clock(tid, reuse_count)
> >> + : fast_state(tid, epoch)
> >> + // Do not touch these, rely on zero initialization,
> >> + // they may be accessed before the ctor.
> >> + // , ignore_reads_and_writes()
> >> + // , ignore_interceptors()
> >> + ,
> >> + clock(tid, reuse_count)
> >> #if !SANITIZER_GO
> >> - , jmp_bufs()
> >> + ,
> >> + jmp_bufs()
> >> #endif
> >> - , tid(tid)
> >> - , unique_id(unique_id)
> >> - , stk_addr(stk_addr)
> >> - , stk_size(stk_size)
> >> - , tls_addr(tls_addr)
> >> - , tls_size(tls_size)
> >> + ,
> >> + tid(tid),
> >> + unique_id(unique_id),
> >> + stk_addr(stk_addr),
> >> + stk_size(stk_size),
> >> + tls_addr(tls_addr),
> >> + tls_size(tls_size)
> >> #if !SANITIZER_GO
> >> - , last_sleep_clock(tid)
> >> + ,
> >> + last_sleep_clock(tid)
> >> #endif
> >> {
> >> }
> >> @@ -160,12 +183,12 @@ static void *BackgroundThread(void *arg) {
> >> } else if (internal_strcmp(flags()->profile_memory, "stderr") == 0) {
> >> mprof_fd = 2;
> >> } else {
> >> - InternalScopedString filename(kMaxPathLength);
> >> + InternalScopedString filename;
> >> filename.append("%s.%d", flags()->profile_memory, (int)internal_getpid());
> >> fd_t fd = OpenFile(filename.data(), WrOnly);
> >> if (fd == kInvalidFd) {
> >> Printf("ThreadSanitizer: failed to open memory profile file '%s'\n",
> >> - &filename[0]);
> >> + filename.data());
> >> } else {
> >> mprof_fd = fd;
> >> }
> >> @@ -351,6 +374,18 @@ static void TsanOnDeadlySignal(int signo, void *siginfo, void *context) {
> >> }
> >> #endif
> >>
> >> +void CheckUnwind() {
> >> + // There is high probability that interceptors will check-fail as well,
> >> + // on the other hand there is no sense in processing interceptors
> >> + // since we are going to die soon.
> >> + ScopedIgnoreInterceptors ignore;
> >> +#if !SANITIZER_GO
> >> + cur_thread()->ignore_sync++;
> >> + cur_thread()->ignore_reads_and_writes++;
> >> +#endif
> >> + PrintCurrentStackSlow(StackTrace::GetCurrentPc());
> >> +}
> >> +
> >> void Initialize(ThreadState *thr) {
> >> // Thread safe because done before all threads exist.
> >> static bool is_initialized = false;
> >> @@ -361,7 +396,7 @@ void Initialize(ThreadState *thr) {
> >> ScopedIgnoreInterceptors ignore;
> >> SanitizerToolName = "ThreadSanitizer";
> >> // Install tool-specific callbacks in sanitizer_common.
> >> - SetCheckFailedCallback(TsanCheckFailed);
> >> + SetCheckUnwindCallback(CheckUnwind);
> >>
> >> ctx = new(ctx_placeholder) Context;
> >> const char *env_name = SANITIZER_GO ? "GORACE" : "TSAN_OPTIONS";
> >> @@ -499,23 +534,27 @@ int Finalize(ThreadState *thr) {
> >> void ForkBefore(ThreadState *thr, uptr pc) {
> >> ctx->thread_registry->Lock();
> >> ctx->report_mtx.Lock();
> >> - // Ignore memory accesses in the pthread_atfork callbacks.
> >> - // If any of them triggers a data race we will deadlock
> >> - // on the report_mtx.
> >> - // We could ignore interceptors and sync operations as well,
> >> + // Suppress all reports in the pthread_atfork callbacks.
> >> + // Reports will deadlock on the report_mtx.
> >> + // We could ignore sync operations as well,
> >> // but so far it's unclear if it will do more good or harm.
> >> // Unnecessarily ignoring things can lead to false positives later.
> >> - ThreadIgnoreBegin(thr, pc);
> >> + thr->suppress_reports++;
> >> + // On OS X, REAL(fork) can call intercepted functions (OSSpinLockLock), and
> >> + // we'll assert in CheckNoLocks() unless we ignore interceptors.
> >> + thr->ignore_interceptors++;
> >> }
> >>
> >> void ForkParentAfter(ThreadState *thr, uptr pc) {
> >> - ThreadIgnoreEnd(thr, pc); // Begin is in ForkBefore.
> >> + thr->suppress_reports--; // Enabled in ForkBefore.
> >> + thr->ignore_interceptors--;
> >> ctx->report_mtx.Unlock();
> >> ctx->thread_registry->Unlock();
> >> }
> >>
> >> void ForkChildAfter(ThreadState *thr, uptr pc) {
> >> - ThreadIgnoreEnd(thr, pc); // Begin is in ForkBefore.
> >> + thr->suppress_reports--; // Enabled in ForkBefore.
> >> + thr->ignore_interceptors--;
> >> ctx->report_mtx.Unlock();
> >> ctx->thread_registry->Unlock();
> >>
> >> diff --git a/libsanitizer/tsan/tsan_rtl.h b/libsanitizer/tsan/tsan_rtl.h
> >> index 04d474e044e..3ae519d34da 100644
> >> --- a/libsanitizer/tsan/tsan_rtl.h
> >> +++ b/libsanitizer/tsan/tsan_rtl.h
> >> @@ -84,9 +84,6 @@ typedef Allocator::AllocatorCache AllocatorCache;
> >> Allocator *allocator();
> >> #endif
> >>
> >> -void TsanCheckFailed(const char *file, int line, const char *cond,
> >> - u64 v1, u64 v2);
> >> -
> >> const u64 kShadowRodata = (u64)-1; // .rodata shadow marker
> >>
> >> // FastState (from most significant bit):
> >> @@ -406,7 +403,7 @@ struct ThreadState {
> >> #if TSAN_COLLECT_STATS
> >> u64 stat[StatCnt];
> >> #endif
> >> - const int tid;
> >> + const u32 tid;
> >> const int unique_id;
> >> bool in_symbolizer;
> >> bool in_ignored_lib;
> >> @@ -447,9 +444,8 @@ struct ThreadState {
> >>
> >> const ReportDesc *current_report;
> >>
> >> - explicit ThreadState(Context *ctx, int tid, int unique_id, u64 epoch,
> >> - unsigned reuse_count,
> >> - uptr stk_addr, uptr stk_size,
> >> + explicit ThreadState(Context *ctx, u32 tid, int unique_id, u64 epoch,
> >> + unsigned reuse_count, uptr stk_addr, uptr stk_size,
> >> uptr tls_addr, uptr tls_size);
> >> };
> >>
> >> @@ -624,6 +620,7 @@ class ScopedReport : public ScopedReportBase {
> >> ScopedErrorReportLock lock_;
> >> };
> >>
> >> +bool ShouldReport(ThreadState *thr, ReportType typ);
> >> ThreadContext *IsThreadStackOrTls(uptr addr, bool *is_stack);
> >> void RestoreStack(int tid, const u64 epoch, VarSizeStackTrace *stk,
> >> MutexSet *mset, uptr *tag = nullptr);
> >> diff --git a/libsanitizer/tsan/tsan_rtl_mutex.cpp b/libsanitizer/tsan/tsan_rtl_mutex.cpp
> >> index 27897f0592b..0a8f3aa3ddb 100644
> >> --- a/libsanitizer/tsan/tsan_rtl_mutex.cpp
> >> +++ b/libsanitizer/tsan/tsan_rtl_mutex.cpp
> >> @@ -51,6 +51,8 @@ static void ReportMutexMisuse(ThreadState *thr, uptr pc, ReportType typ,
> >> // or false positives (e.g. unlock in a different thread).
> >> if (SANITIZER_GO)
> >> return;
> >> + if (!ShouldReport(thr, typ))
> >> + return;
> >> ThreadRegistryLock l(ctx->thread_registry);
> >> ScopedReport rep(typ);
> >> rep.AddMutex(mid);
> >> @@ -96,9 +98,8 @@ void MutexDestroy(ThreadState *thr, uptr pc, uptr addr, u32 flagz) {
> >> ctx->dd->MutexInit(&cb, &s->dd);
> >> }
> >> bool unlock_locked = false;
> >> - if (flags()->report_destroy_locked
> >> - && s->owner_tid != SyncVar::kInvalidTid
> >> - && !s->IsFlagSet(MutexFlagBroken)) {
> >> + if (flags()->report_destroy_locked && s->owner_tid != kInvalidTid &&
> >> + !s->IsFlagSet(MutexFlagBroken)) {
> >> s->SetFlags(MutexFlagBroken);
> >> unlock_locked = true;
> >> }
> >> @@ -107,7 +108,7 @@ void MutexDestroy(ThreadState *thr, uptr pc, uptr addr, u32 flagz) {
> >> if (!unlock_locked)
> >> s->Reset(thr->proc()); // must not reset it before the report is printed
> >> s->mtx.Unlock();
> >> - if (unlock_locked) {
> >> + if (unlock_locked && ShouldReport(thr, ReportTypeMutexDestroyLocked)) {
> >> ThreadRegistryLock l(ctx->thread_registry);
> >> ScopedReport rep(ReportTypeMutexDestroyLocked);
> >> rep.AddMutex(mid);
> >> @@ -169,7 +170,7 @@ void MutexPostLock(ThreadState *thr, uptr pc, uptr addr, u32 flagz, int rec) {
> >> thr->fast_state.IncrementEpoch();
> >> TraceAddEvent(thr, thr->fast_state, EventTypeLock, s->GetId());
> >> bool report_double_lock = false;
> >> - if (s->owner_tid == SyncVar::kInvalidTid) {
> >> + if (s->owner_tid == kInvalidTid) {
> >> CHECK_EQ(s->recursion, 0);
> >> s->owner_tid = thr->tid;
> >> s->last_lock = thr->fast_state.raw();
> >> @@ -229,7 +230,7 @@ int MutexUnlock(ThreadState *thr, uptr pc, uptr addr, u32 flagz) {
> >> s->recursion -= rec;
> >> if (s->recursion == 0) {
> >> StatInc(thr, StatMutexUnlock);
> >> - s->owner_tid = SyncVar::kInvalidTid;
> >> + s->owner_tid = kInvalidTid;
> >> ReleaseStoreImpl(thr, pc, &s->clock);
> >> } else {
> >> StatInc(thr, StatMutexRecUnlock);
> >> @@ -275,7 +276,7 @@ void MutexPostReadLock(ThreadState *thr, uptr pc, uptr addr, u32 flagz) {
> >> thr->fast_state.IncrementEpoch();
> >> TraceAddEvent(thr, thr->fast_state, EventTypeRLock, s->GetId());
> >> bool report_bad_lock = false;
> >> - if (s->owner_tid != SyncVar::kInvalidTid) {
> >> + if (s->owner_tid != kInvalidTid) {
> >> if (flags()->report_mutex_bugs && !s->IsFlagSet(MutexFlagBroken)) {
> >> s->SetFlags(MutexFlagBroken);
> >> report_bad_lock = true;
> >> @@ -314,7 +315,7 @@ void MutexReadUnlock(ThreadState *thr, uptr pc, uptr addr) {
> >> thr->fast_state.IncrementEpoch();
> >> TraceAddEvent(thr, thr->fast_state, EventTypeRUnlock, s->GetId());
> >> bool report_bad_unlock = false;
> >> - if (s->owner_tid != SyncVar::kInvalidTid) {
> >> + if (s->owner_tid != kInvalidTid) {
> >> if (flags()->report_mutex_bugs && !s->IsFlagSet(MutexFlagBroken)) {
> >> s->SetFlags(MutexFlagBroken);
> >> report_bad_unlock = true;
> >> @@ -344,7 +345,7 @@ void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr) {
> >> SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true);
> >> bool write = true;
> >> bool report_bad_unlock = false;
> >> - if (s->owner_tid == SyncVar::kInvalidTid) {
> >> + if (s->owner_tid == kInvalidTid) {
> >> // Seems to be read unlock.
> >> write = false;
> >> StatInc(thr, StatMutexReadUnlock);
> >> @@ -359,7 +360,7 @@ void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr) {
> >> s->recursion--;
> >> if (s->recursion == 0) {
> >> StatInc(thr, StatMutexUnlock);
> >> - s->owner_tid = SyncVar::kInvalidTid;
> >> + s->owner_tid = kInvalidTid;
> >> ReleaseStoreImpl(thr, pc, &s->clock);
> >> } else {
> >> StatInc(thr, StatMutexRecUnlock);
> >> @@ -387,7 +388,7 @@ void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr) {
> >> void MutexRepair(ThreadState *thr, uptr pc, uptr addr) {
> >> DPrintf("#%d: MutexRepair %zx\n", thr->tid, addr);
> >> SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true);
> >> - s->owner_tid = SyncVar::kInvalidTid;
> >> + s->owner_tid = kInvalidTid;
> >> s->recursion = 0;
> >> s->mtx.Unlock();
> >> }
> >> @@ -534,7 +535,7 @@ void AcquireReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c) {
> >> }
> >>
> >> void ReportDeadlock(ThreadState *thr, uptr pc, DDReport *r) {
> >> - if (r == 0)
> >> + if (r == 0 || !ShouldReport(thr, ReportTypeDeadlock))
> >> return;
> >> ThreadRegistryLock l(ctx->thread_registry);
> >> ScopedReport rep(ReportTypeDeadlock);
> >> diff --git a/libsanitizer/tsan/tsan_rtl_ppc64.S b/libsanitizer/tsan/tsan_rtl_ppc64.S
> >> index 9e533a71a9c..8285e21aa1e 100644
> >> --- a/libsanitizer/tsan/tsan_rtl_ppc64.S
> >> +++ b/libsanitizer/tsan/tsan_rtl_ppc64.S
> >> @@ -1,6 +1,5 @@
> >> #include "tsan_ppc_regs.h"
> >>
> >> - .machine altivec
> >> .section .text
> >> .hidden __tsan_setjmp
> >> .globl _setjmp
> >> diff --git a/libsanitizer/tsan/tsan_rtl_report.cpp b/libsanitizer/tsan/tsan_rtl_report.cpp
> >> index 208d0df44df..706794fdad1 100644
> >> --- a/libsanitizer/tsan/tsan_rtl_report.cpp
> >> +++ b/libsanitizer/tsan/tsan_rtl_report.cpp
> >> @@ -31,23 +31,6 @@ using namespace __sanitizer;
> >>
> >> static ReportStack *SymbolizeStack(StackTrace trace);
> >>
> >> -void TsanCheckFailed(const char *file, int line, const char *cond,
> >> - u64 v1, u64 v2) {
> >> - // There is high probability that interceptors will check-fail as well,
> >> - // on the other hand there is no sense in processing interceptors
> >> - // since we are going to die soon.
> >> - ScopedIgnoreInterceptors ignore;
> >> -#if !SANITIZER_GO
> >> - cur_thread()->ignore_sync++;
> >> - cur_thread()->ignore_reads_and_writes++;
> >> -#endif
> >> - Printf("FATAL: ThreadSanitizer CHECK failed: "
> >> - "%s:%d \"%s\" (0x%zx, 0x%zx)\n",
> >> - file, line, cond, (uptr)v1, (uptr)v2);
> >> - PrintCurrentStackSlow(StackTrace::GetCurrentPc());
> >> - Die();
> >> -}
> >> -
> >> // Can be overriden by an application/test to intercept reports.
> >> #ifdef TSAN_EXTERNAL_HOOKS
> >> bool OnReport(const ReportDesc *rep, bool suppressed);
> >> @@ -142,6 +125,34 @@ static ReportStack *SymbolizeStack(StackTrace trace) {
> >> return stack;
> >> }
> >>
> >> +bool ShouldReport(ThreadState *thr, ReportType typ) {
> >> + // We set thr->suppress_reports in the fork context.
> >> + // Taking any locking in the fork context can lead to deadlocks.
> >> + // If any locks are already taken, it's too late to do this check.
> >> + CheckNoLocks(thr);
> >> + // For the same reason check we didn't lock thread_registry yet.
> >> + if (SANITIZER_DEBUG)
> >> + ThreadRegistryLock l(ctx->thread_registry);
> >> + if (!flags()->report_bugs || thr->suppress_reports)
> >> + return false;
> >> + switch (typ) {
> >> + case ReportTypeSignalUnsafe:
> >> + return flags()->report_signal_unsafe;
> >> + case ReportTypeThreadLeak:
> >> +#if !SANITIZER_GO
> >> + // It's impossible to join phantom threads
> >> + // in the child after fork.
> >> + if (ctx->after_multithreaded_fork)
> >> + return false;
> >> +#endif
> >> + return flags()->report_thread_leaks;
> >> + case ReportTypeMutexDestroyLocked:
> >> + return flags()->report_destroy_locked;
> >> + default:
> >> + return true;
> >> + }
> >> +}
> >> +
> >> ScopedReportBase::ScopedReportBase(ReportType typ, uptr tag) {
> >> ctx->thread_registry->CheckLocked();
> >> void *mem = internal_alloc(MBlockReport, sizeof(ReportDesc));
> >> @@ -497,8 +508,10 @@ static bool HandleRacyAddress(ThreadState *thr, uptr addr_min, uptr addr_max) {
> >> }
> >>
> >> bool OutputReport(ThreadState *thr, const ScopedReport &srep) {
> >> - if (!flags()->report_bugs || thr->suppress_reports)
> >> - return false;
> >> + // These should have been checked in ShouldReport.
> >> + // It's too late to check them here, we have already taken locks.
> >> + CHECK(flags()->report_bugs);
> >> + CHECK(!thr->suppress_reports);
> >> atomic_store_relaxed(&ctx->last_symbolize_time_ns, NanoTime());
> >> const ReportDesc *rep = srep.GetReport();
> >> CHECK_EQ(thr->current_report, nullptr);
> >> @@ -589,7 +602,7 @@ void ReportRace(ThreadState *thr) {
> >> // at best it will cause deadlocks on internal mutexes.
> >> ScopedIgnoreInterceptors ignore;
> >>
> >> - if (!flags()->report_bugs)
> >> + if (!ShouldReport(thr, ReportTypeRace))
> >> return;
> >> if (!flags()->report_atomic_races && !RaceBetweenAtomicAndFree(thr))
> >> return;
> >> @@ -722,8 +735,7 @@ void PrintCurrentStack(ThreadState *thr, uptr pc) {
> >> // However, this solution is not reliable enough, please see dvyukov's comment
> >> // http://reviews.llvm.org/D19148#406208
> >> // Also see PR27280 comment 2 and 3 for breaking examples and analysis.
> >> -ALWAYS_INLINE
> >> -void PrintCurrentStackSlow(uptr pc) {
> >> +ALWAYS_INLINE USED void PrintCurrentStackSlow(uptr pc) {
> >> #if !SANITIZER_GO
> >> uptr bp = GET_CURRENT_FRAME();
> >> BufferedStackTrace *ptrace =
> >> diff --git a/libsanitizer/tsan/tsan_rtl_thread.cpp b/libsanitizer/tsan/tsan_rtl_thread.cpp
> >> index d80146735ea..6d1ccd8c9c7 100644
> >> --- a/libsanitizer/tsan/tsan_rtl_thread.cpp
> >> +++ b/libsanitizer/tsan/tsan_rtl_thread.cpp
> >> @@ -51,7 +51,7 @@ struct OnCreatedArgs {
> >>
> >> void ThreadContext::OnCreated(void *arg) {
> >> thr = 0;
> >> - if (tid == 0)
> >> + if (tid == kMainTid)
> >> return;
> >> OnCreatedArgs *args = static_cast<OnCreatedArgs *>(arg);
> >> if (!args->thr) // GCD workers don't have a parent thread.
> >> @@ -179,7 +179,7 @@ static void MaybeReportThreadLeak(ThreadContextBase *tctx_base, void *arg) {
> >>
> >> #if !SANITIZER_GO
> >> static void ReportIgnoresEnabled(ThreadContext *tctx, IgnoreSet *set) {
> >> - if (tctx->tid == 0) {
> >> + if (tctx->tid == kMainTid) {
> >> Printf("ThreadSanitizer: main thread finished with ignores enabled\n");
> >> } else {
> >> Printf("ThreadSanitizer: thread T%d %s finished with ignores enabled,"
> >> @@ -210,7 +210,7 @@ static void ThreadCheckIgnore(ThreadState *thr) {}
> >> void ThreadFinalize(ThreadState *thr) {
> >> ThreadCheckIgnore(thr);
> >> #if !SANITIZER_GO
> >> - if (!flags()->report_thread_leaks)
> >> + if (!ShouldReport(thr, ReportTypeThreadLeak))
> >> return;
> >> ThreadRegistryLock l(ctx->thread_registry);
> >> Vector<ThreadLeak> leaks;
> >> @@ -250,9 +250,10 @@ void ThreadStart(ThreadState *thr, int tid, tid_t os_id,
> >> uptr tls_size = 0;
> >> #if !SANITIZER_GO
> >> if (thread_type != ThreadType::Fiber)
> >> - GetThreadStackAndTls(tid == 0, &stk_addr, &stk_size, &tls_addr, &tls_size);
> >> + GetThreadStackAndTls(tid == kMainTid, &stk_addr, &stk_size, &tls_addr,
> >> + &tls_size);
> >>
> >> - if (tid) {
> >> + if (tid != kMainTid) {
> >> if (stk_addr && stk_size)
> >> MemoryRangeImitateWrite(thr, /*pc=*/ 1, stk_addr, stk_size);
> >>
> >> @@ -313,7 +314,7 @@ static bool ConsumeThreadByUid(ThreadContextBase *tctx, void *arg) {
> >> int ThreadConsumeTid(ThreadState *thr, uptr pc, uptr uid) {
> >> ConsumeThreadContext findCtx = {uid, nullptr};
> >> ctx->thread_registry->FindThread(ConsumeThreadByUid, &findCtx);
> >> - int tid = findCtx.tctx ? findCtx.tctx->tid : ThreadRegistry::kUnknownTid;
> >> + int tid = findCtx.tctx ? findCtx.tctx->tid : kInvalidTid;
> >> DPrintf("#%d: ThreadTid uid=%zu tid=%d\n", thr->tid, uid, tid);
> >> return tid;
> >> }
> >> diff --git a/libsanitizer/tsan/tsan_sync.cpp b/libsanitizer/tsan/tsan_sync.cpp
> >> index 17ddd50f128..ba24f98ae9f 100644
> >> --- a/libsanitizer/tsan/tsan_sync.cpp
> >> +++ b/libsanitizer/tsan/tsan_sync.cpp
> >> @@ -53,8 +53,8 @@ void SyncVar::Reset(Processor *proc) {
> >> }
> >>
> >> MetaMap::MetaMap()
> >> - : block_alloc_("heap block allocator")
> >> - , sync_alloc_("sync allocator") {
> >> + : block_alloc_(LINKER_INITIALIZED, "heap block allocator"),
> >> + sync_alloc_(LINKER_INITIALIZED, "sync allocator") {
> >> atomic_store(&uid_gen_, 0, memory_order_relaxed);
> >> }
> >>
> >> diff --git a/libsanitizer/tsan/tsan_sync.h b/libsanitizer/tsan/tsan_sync.h
> >> index 47f2739d8de..c4056f684d7 100644
> >> --- a/libsanitizer/tsan/tsan_sync.h
> >> +++ b/libsanitizer/tsan/tsan_sync.h
> >> @@ -50,13 +50,11 @@ enum MutexFlags {
> >> struct SyncVar {
> >> SyncVar();
> >>
> >> - static const int kInvalidTid = -1;
> >> -
> >> uptr addr; // overwritten by DenseSlabAlloc freelist
> >> Mutex mtx;
> >> u64 uid; // Globally unique id.
> >> u32 creation_stack_id;
> >> - int owner_tid; // Set only by exclusive owners.
> >> + u32 owner_tid; // Set only by exclusive owners.
> >> u64 last_lock;
> >> int recursion;
> >> atomic_uint32_t flags;
> >> @@ -130,8 +128,8 @@ class MetaMap {
> >> static const u32 kFlagMask = 3u << 30;
> >> static const u32 kFlagBlock = 1u << 30;
> >> static const u32 kFlagSync = 2u << 30;
> >> - typedef DenseSlabAlloc<MBlock, 1<<16, 1<<12> BlockAlloc;
> >> - typedef DenseSlabAlloc<SyncVar, 1<<16, 1<<10> SyncAlloc;
> >> + typedef DenseSlabAlloc<MBlock, 1 << 18, 1 << 12, kFlagMask> BlockAlloc;
> >> + typedef DenseSlabAlloc<SyncVar, 1 << 20, 1 << 10, kFlagMask> SyncAlloc;
> >> BlockAlloc block_alloc_;
> >> SyncAlloc sync_alloc_;
> >> atomic_uint64_t uid_gen_;
> >> diff --git a/libsanitizer/ubsan/ubsan_diag.cpp b/libsanitizer/ubsan/ubsan_diag.cpp
> >> index 1b2828d236d..ef2e495cac8 100644
> >> --- a/libsanitizer/ubsan/ubsan_diag.cpp
> >> +++ b/libsanitizer/ubsan/ubsan_diag.cpp
> >> @@ -278,7 +278,7 @@ static void PrintMemorySnippet(const Decorator &Decor, MemoryLocation Loc,
> >> }
> >>
> >> // Emit data.
> >> - InternalScopedString Buffer(1024);
> >> + InternalScopedString Buffer;
> >> for (uptr P = Min; P != Max; ++P) {
> >> unsigned char C = *reinterpret_cast<const unsigned char*>(P);
> >> Buffer.append("%s%02x", (P % 8 == 0) ? " " : " ", C);
> >> @@ -346,7 +346,7 @@ Diag::~Diag() {
> >> // All diagnostics should be printed under report mutex.
> >> ScopedReport::CheckLocked();
> >> Decorator Decor;
> >> - InternalScopedString Buffer(1024);
> >> + InternalScopedString Buffer;
> >>
> >> // Prepare a report that a monitor process can inspect.
> >> if (Level == DL_Error) {
> >> @@ -388,6 +388,10 @@ ScopedReport::ScopedReport(ReportOptions Opts, Location SummaryLoc,
> >> ScopedReport::~ScopedReport() {
> >> MaybePrintStackTrace(Opts.pc, Opts.bp);
> >> MaybeReportErrorSummary(SummaryLoc, Type);
> >> +
> >> + if (common_flags()->print_module_map >= 2)
> >> + DumpProcessMap();
> >> +
> >> if (flags()->halt_on_error)
> >> Die();
> >> }
> >> diff --git a/libsanitizer/ubsan/ubsan_flags.cpp b/libsanitizer/ubsan/ubsan_flags.cpp
> >> index 9a66bd37518..25cefd46ce2 100644
> >> --- a/libsanitizer/ubsan/ubsan_flags.cpp
> >> +++ b/libsanitizer/ubsan/ubsan_flags.cpp
> >> @@ -50,7 +50,6 @@ void InitializeFlags() {
> >> {
> >> CommonFlags cf;
> >> cf.CopyFrom(*common_flags());
> >> - cf.print_summary = false;
> >> cf.external_symbolizer_path = GetFlag("UBSAN_SYMBOLIZER_PATH");
> >> OverrideCommonFlags(cf);
> >> }
> >> diff --git a/libsanitizer/ubsan/ubsan_handlers.cpp b/libsanitizer/ubsan/ubsan_handlers.cpp
> >> index 2184625aa6e..e201e6bba22 100644
> >> --- a/libsanitizer/ubsan/ubsan_handlers.cpp
> >> +++ b/libsanitizer/ubsan/ubsan_handlers.cpp
> >> @@ -894,21 +894,6 @@ void __ubsan_handle_cfi_bad_type(CFICheckFailData *Data, ValueHandle Vtable,
> >>
> >> } // namespace __ubsan
> >>
> >> -void __ubsan::__ubsan_handle_cfi_bad_icall(CFIBadIcallData *CallData,
> >> - ValueHandle Function) {
> >> - GET_REPORT_OPTIONS(false);
> >> - CFICheckFailData Data = {CFITCK_ICall, CallData->Loc, CallData->Type};
> >> - handleCFIBadIcall(&Data, Function, Opts);
> >> -}
> >> -
> >> -void __ubsan::__ubsan_handle_cfi_bad_icall_abort(CFIBadIcallData *CallData,
> >> - ValueHandle Function) {
> >> - GET_REPORT_OPTIONS(true);
> >> - CFICheckFailData Data = {CFITCK_ICall, CallData->Loc, CallData->Type};
> >> - handleCFIBadIcall(&Data, Function, Opts);
> >> - Die();
> >> -}
> >> -
> >> void __ubsan::__ubsan_handle_cfi_check_fail(CFICheckFailData *Data,
> >> ValueHandle Value,
> >> uptr ValidVtable) {
> >> diff --git a/libsanitizer/ubsan/ubsan_handlers.h b/libsanitizer/ubsan/ubsan_handlers.h
> >> index 9f412353fc0..219fb15de55 100644
> >> --- a/libsanitizer/ubsan/ubsan_handlers.h
> >> +++ b/libsanitizer/ubsan/ubsan_handlers.h
> >> @@ -215,20 +215,12 @@ enum CFITypeCheckKind : unsigned char {
> >> CFITCK_VMFCall,
> >> };
> >>
> >> -struct CFIBadIcallData {
> >> - SourceLocation Loc;
> >> - const TypeDescriptor &Type;
> >> -};
> >> -
> >> struct CFICheckFailData {
> >> CFITypeCheckKind CheckKind;
> >> SourceLocation Loc;
> >> const TypeDescriptor &Type;
> >> };
> >>
> >> -/// \brief Handle control flow integrity failure for indirect function calls.
> >> -RECOVERABLE(cfi_bad_icall, CFIBadIcallData *Data, ValueHandle Function)
> >> -
> >> /// \brief Handle control flow integrity failures.
> >> RECOVERABLE(cfi_check_fail, CFICheckFailData *Data, ValueHandle Function,
> >> uptr VtableIsValid)
> >> diff --git a/libsanitizer/ubsan/ubsan_init.cpp b/libsanitizer/ubsan/ubsan_init.cpp
> >> index e0be5a72ec4..9931d85bf40 100644
> >> --- a/libsanitizer/ubsan/ubsan_init.cpp
> >> +++ b/libsanitizer/ubsan/ubsan_init.cpp
> >> @@ -33,6 +33,11 @@ static void CommonInit() {
> >> InitializeSuppressions();
> >> }
> >>
> >> +static void UbsanDie() {
> >> + if (common_flags()->print_module_map >= 1)
> >> + DumpProcessMap();
> >> +}
> >> +
> >> static void CommonStandaloneInit() {
> >> SanitizerToolName = GetSanititizerToolName();
> >> CacheBinaryName();
> >> @@ -42,6 +47,10 @@ static void CommonStandaloneInit() {
> >> AndroidLogInit();
> >> InitializeCoverage(common_flags()->coverage, common_flags()->coverage_dir);
> >> CommonInit();
> >> +
> >> + // Only add die callback when running in standalone mode to avoid printing
> >> + // the same information from multiple sanitizers' output
> >> + AddDieCallback(UbsanDie);
> >> Symbolizer::LateInitialize();
> >> }
> >>
> >> diff --git a/libsanitizer/ubsan/ubsan_monitor.cpp b/libsanitizer/ubsan/ubsan_monitor.cpp
> >> index d064e95f76f..69dd986f9bd 100644
> >> --- a/libsanitizer/ubsan/ubsan_monitor.cpp
> >> +++ b/libsanitizer/ubsan/ubsan_monitor.cpp
> >> @@ -17,7 +17,7 @@ using namespace __ubsan;
> >> UndefinedBehaviorReport::UndefinedBehaviorReport(const char *IssueKind,
> >> Location &Loc,
> >> InternalScopedString &Msg)
> >> - : IssueKind(IssueKind), Loc(Loc), Buffer(Msg.length() + 1) {
> >> + : IssueKind(IssueKind), Loc(Loc) {
> >> // We have the common sanitizer reporting lock, so it's safe to register a
> >> // new UB report.
> >> RegisterUndefinedBehaviorReport(this);
> >> @@ -52,9 +52,9 @@ void __ubsan::__ubsan_get_current_report_data(const char **OutIssueKind,
> >>
> >> // Ensure that the first character of the diagnostic text can't start with a
> >> // lowercase letter.
> >> - char FirstChar = Buf.data()[0];
> >> + char FirstChar = *Buf.data();
> >> if (FirstChar >= 'a' && FirstChar <= 'z')
> >> - Buf.data()[0] = FirstChar - 'a' + 'A';
> >> + *Buf.data() += 'A' - 'a';
> >>
> >> *OutIssueKind = CurrentUBR->IssueKind;
> >> *OutMessage = Buf.data();
> >> diff --git a/libsanitizer/ubsan/ubsan_platform.h b/libsanitizer/ubsan/ubsan_platform.h
> >> index 98542fcea96..51e535d1e22 100644
> >> --- a/libsanitizer/ubsan/ubsan_platform.h
> >> +++ b/libsanitizer/ubsan/ubsan_platform.h
> >> @@ -12,16 +12,14 @@
> >> #ifndef UBSAN_PLATFORM_H
> >> #define UBSAN_PLATFORM_H
> >>
> >> -#ifndef CAN_SANITIZE_UB
> >> // Other platforms should be easy to add, and probably work as-is.
> >> #if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || \
> >> - defined(__NetBSD__) || \
> >> + defined(__NetBSD__) || defined(__DragonFly__) || \
> >> (defined(__sun__) && defined(__svr4__)) || \
> >> defined(_WIN32) || defined(__Fuchsia__) || defined(__rtems__)
> >> # define CAN_SANITIZE_UB 1
> >> #else
> >> # define CAN_SANITIZE_UB 0
> >> #endif
> >> -#endif //CAN_SANITIZE_UB
> >>
> >> #endif
> >
> >> --
> >> 2.31.1
> >>
> >
> >
> > --
> > BR,
> > Hongtao
> >
>
--
BR,
Hongtao
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH] Libsanitizer: merge from master.
@ 2020-06-02 6:00 Martin Liška
2020-06-06 19:47 ` Andreas Schwab
2020-10-16 8:59 ` Martin Liška
0 siblings, 2 replies; 17+ messages in thread
From: Martin Liška @ 2020-06-02 6:00 UTC (permalink / raw)
To: gcc-patches
Merged from revision b638b63b99d66786cb37336292604a2ae3490cfd.
The patch successfully bootstraps on x86_64-linux-gnu and
ppc64le-linux-gnu. I also tested ppc64-linux-gnu that exposed:
https://reviews.llvm.org/D80864 (which is fixed on master).
Abidiff looks happy and I made UBSAN and ASAN bootstrap on
x86_64-linux-gnu.
I'm planning to do merge from master twice a year, once now and
next time short before stage1 closes.
I am going to install the patches as merge from master is obvious
and I haven't made anything special.
libsanitizer/ChangeLog:
* MERGE: Merge from master.
---
libsanitizer/MERGE | 2 +-
libsanitizer/asan/asan_globals.cpp | 19 +
libsanitizer/asan/asan_interceptors.h | 7 +-
libsanitizer/asan/asan_mapping.h | 2 +-
libsanitizer/asan/asan_report.cpp | 3 +
libsanitizer/asan/asan_thread.cpp | 2 +
.../include/sanitizer/linux_syscall_hooks.h | 8 +-
.../include/sanitizer/netbsd_syscall_hooks.h | 2 +-
.../include/sanitizer/tsan_interface.h | 20 +-
libsanitizer/lsan/lsan.cpp | 17 +-
libsanitizer/lsan/lsan.h | 6 +
libsanitizer/lsan/lsan_allocator.h | 5 +-
libsanitizer/lsan/lsan_common.cpp | 51 +-
libsanitizer/lsan/lsan_common.h | 17 +-
libsanitizer/lsan/lsan_common_fuchsia.cpp | 166 +++++
libsanitizer/lsan/lsan_common_linux.cpp | 3 +-
libsanitizer/lsan/lsan_common_mac.cpp | 3 +-
libsanitizer/lsan/lsan_fuchsia.cpp | 123 ++++
libsanitizer/lsan/lsan_fuchsia.h | 35 +
libsanitizer/lsan/lsan_interceptors.cpp | 19 +-
libsanitizer/lsan/lsan_linux.cpp | 6 +-
libsanitizer/lsan/lsan_posix.cpp | 96 +++
libsanitizer/lsan/lsan_posix.h | 49 ++
libsanitizer/lsan/lsan_thread.cpp | 98 +--
libsanitizer/lsan/lsan_thread.h | 35 +-
.../sanitizer_common/sanitizer_allocator.cpp | 4 +-
.../sanitizer_allocator_primary64.h | 10 +-
.../sanitizer_common/sanitizer_common.cpp | 2 +
.../sanitizer_common/sanitizer_common.h | 5 +-
.../sanitizer_common_interceptors.inc | 190 +++++-
...izer_common_interceptors_netbsd_compat.inc | 128 ++++
.../sanitizer_common_libcdep.cpp | 12 +-
.../sanitizer_common_syscalls.inc | 17 +
.../sanitizer_coverage_fuchsia.cpp | 25 +-
.../sanitizer_coverage_interface.inc | 1 +
.../sanitizer_coverage_libcdep_new.cpp | 1 +
.../sanitizer_common/sanitizer_file.h | 4 +-
.../sanitizer_flag_parser.cpp | 11 +-
.../sanitizer_common/sanitizer_flag_parser.h | 49 ++
.../sanitizer_common/sanitizer_flags.cpp | 10 +-
.../sanitizer_common/sanitizer_freebsd.h | 23 +-
.../sanitizer_common/sanitizer_fuchsia.cpp | 4 +
.../sanitizer_common/sanitizer_fuchsia.h | 6 +
.../sanitizer_interceptors_ioctl_netbsd.inc | 18 +-
.../sanitizer_interface_internal.h | 6 +-
.../sanitizer_internal_defs.h | 2 +-
.../sanitizer_common/sanitizer_libc.h | 2 +
.../sanitizer_common/sanitizer_linux.cpp | 151 ++++-
.../sanitizer_common/sanitizer_linux.h | 2 +
.../sanitizer_linux_libcdep.cpp | 17 +-
.../sanitizer_common/sanitizer_linux_s390.cpp | 11 +-
.../sanitizer_common/sanitizer_mac.cpp | 81 ++-
libsanitizer/sanitizer_common/sanitizer_mac.h | 21 +-
.../sanitizer_common/sanitizer_malloc_mac.inc | 18 +-
.../sanitizer_common/sanitizer_netbsd.cpp | 7 +-
.../sanitizer_platform_interceptors.h | 24 +
.../sanitizer_platform_limits_freebsd.cpp | 614 +++++++++---------
.../sanitizer_platform_limits_freebsd.h | 32 +-
.../sanitizer_platform_limits_linux.cpp | 7 +-
.../sanitizer_platform_limits_netbsd.cpp | 191 ++++++
.../sanitizer_platform_limits_netbsd.h | 33 +-
.../sanitizer_platform_limits_openbsd.cpp | 1 +
.../sanitizer_platform_limits_openbsd.h | 1 +
.../sanitizer_platform_limits_posix.cpp | 1 +
.../sanitizer_platform_limits_posix.h | 3 +-
.../sanitizer_platform_limits_solaris.cpp | 1 +
.../sanitizer_platform_limits_solaris.h | 1 +
.../sanitizer_common/sanitizer_posix.cpp | 10 +-
.../sanitizer_common/sanitizer_posix.h | 4 +-
.../sanitizer_posix_libcdep.cpp | 6 +-
.../sanitizer_common/sanitizer_procmaps.h | 7 +-
.../sanitizer_procmaps_fuchsia.cpp | 80 +++
.../sanitizer_common/sanitizer_ptrauth.h | 21 +
.../sanitizer_common/sanitizer_rtems.cpp | 4 +
.../sanitizer_common/sanitizer_stacktrace.cpp | 17 +-
.../sanitizer_stoptheworld_fuchsia.cpp | 42 ++
.../sanitizer_stoptheworld_mac.cpp | 9 +-
.../sanitizer_stoptheworld_netbsd_libcdep.cpp | 12 +-
.../sanitizer_common/sanitizer_symbolizer.cpp | 6 +
.../sanitizer_common/sanitizer_symbolizer.h | 3 +
.../sanitizer_symbolizer_internal.h | 7 +
.../sanitizer_symbolizer_libcdep.cpp | 89 ++-
.../sanitizer_symbolizer_mac.cpp | 88 ++-
.../sanitizer_symbolizer_mac.h | 1 +
.../sanitizer_symbolizer_markup.cpp | 4 +-
.../sanitizer_symbolizer_posix_libcdep.cpp | 16 +-
.../sanitizer_symbolizer_win.cpp | 2 +-
.../sanitizer_syscalls_netbsd.inc | 22 +-
.../sanitizer_common/sanitizer_win.cpp | 9 +-
libsanitizer/tsan/tsan_clock.cpp | 68 +-
libsanitizer/tsan/tsan_clock.h | 58 ++
libsanitizer/tsan/tsan_interceptors_posix.cpp | 21 +-
libsanitizer/tsan/tsan_platform.h | 1 +
libsanitizer/tsan/tsan_platform_mac.cpp | 10 +-
libsanitizer/tsan/tsan_rtl.cpp | 12 +-
libsanitizer/tsan/tsan_rtl.h | 4 +-
libsanitizer/tsan/tsan_rtl_mutex.cpp | 25 +-
libsanitizer/tsan/tsan_rtl_ppc64.S | 1 -
libsanitizer/tsan/tsan_rtl_thread.cpp | 34 +-
libsanitizer/tsan/tsan_stat.h | 1 +
libsanitizer/ubsan/ubsan_checks.inc | 6 +
libsanitizer/ubsan/ubsan_flags.cpp | 1 -
libsanitizer/ubsan/ubsan_handlers.cpp | 65 +-
libsanitizer/ubsan/ubsan_handlers.h | 8 -
libsanitizer/ubsan/ubsan_init.cpp | 2 +
libsanitizer/ubsan/ubsan_platform.h | 2 -
.../ubsan/ubsan_type_hash_itanium.cpp | 2 +
107 files changed, 2551 insertions(+), 770 deletions(-)
create mode 100644 libsanitizer/lsan/lsan_common_fuchsia.cpp
create mode 100644 libsanitizer/lsan/lsan_fuchsia.cpp
create mode 100644 libsanitizer/lsan/lsan_fuchsia.h
create mode 100644 libsanitizer/lsan/lsan_posix.cpp
create mode 100644 libsanitizer/lsan/lsan_posix.h
create mode 100644 libsanitizer/sanitizer_common/sanitizer_common_interceptors_netbsd_compat.inc
create mode 100644 libsanitizer/sanitizer_common/sanitizer_procmaps_fuchsia.cpp
create mode 100644 libsanitizer/sanitizer_common/sanitizer_ptrauth.h
create mode 100644 libsanitizer/sanitizer_common/sanitizer_stoptheworld_fuchsia.cpp
diff --git a/libsanitizer/MERGE b/libsanitizer/MERGE
index 49ee2c3bab8..e14e830ea7d 100644
--- a/libsanitizer/MERGE
+++ b/libsanitizer/MERGE
@@ -1,4 +1,4 @@
-82588e05cc32bb30807e480abd4e689b0dee132a
+b638b63b99d66786cb37336292604a2ae3490cfd
The first line of this file holds the git revision number of the
last merge done from the master library sources.
diff --git a/libsanitizer/asan/asan_globals.cpp b/libsanitizer/asan/asan_globals.cpp
index e045c31cd1c..9d7dbc6f264 100644
--- a/libsanitizer/asan/asan_globals.cpp
+++ b/libsanitizer/asan/asan_globals.cpp
@@ -154,6 +154,23 @@ static void CheckODRViolationViaIndicator(const Global *g) {
}
}
+// Check ODR violation for given global G by checking if it's already poisoned.
+// We use this method in case compiler doesn't use private aliases for global
+// variables.
+static void CheckODRViolationViaPoisoning(const Global *g) {
+ if (__asan_region_is_poisoned(g->beg, g->size_with_redzone)) {
+ // This check may not be enough: if the first global is much larger
+ // the entire redzone of the second global may be within the first global.
+ for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) {
+ if (g->beg == l->g->beg &&
+ (flags()->detect_odr_violation >= 2 || g->size != l->g->size) &&
+ !IsODRViolationSuppressed(g->name))
+ ReportODRViolation(g, FindRegistrationSite(g),
+ l->g, FindRegistrationSite(l->g));
+ }
+ }
+}
+
// Clang provides two different ways for global variables protection:
// it can poison the global itself or its private alias. In former
// case we may poison same symbol multiple times, that can help us to
@@ -199,6 +216,8 @@ static void RegisterGlobal(const Global *g) {
// where two globals with the same name are defined in different modules.
if (UseODRIndicator(g))
CheckODRViolationViaIndicator(g);
+ else
+ CheckODRViolationViaPoisoning(g);
}
if (CanPoisonMemory())
PoisonRedZones(*g);
diff --git a/libsanitizer/asan/asan_interceptors.h b/libsanitizer/asan/asan_interceptors.h
index b7a85fedbdf..344a64bd83d 100644
--- a/libsanitizer/asan/asan_interceptors.h
+++ b/libsanitizer/asan/asan_interceptors.h
@@ -80,12 +80,7 @@ void InitializePlatformInterceptors();
#if ASAN_HAS_EXCEPTIONS && !SANITIZER_WINDOWS && !SANITIZER_SOLARIS && \
!SANITIZER_NETBSD
# define ASAN_INTERCEPT___CXA_THROW 1
-# if ! defined(ASAN_HAS_CXA_RETHROW_PRIMARY_EXCEPTION) \
- || ASAN_HAS_CXA_RETHROW_PRIMARY_EXCEPTION
-# define ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION 1
-# else
-# define ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION 0
-# endif
+# define ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION 1
# if defined(_GLIBCXX_SJLJ_EXCEPTIONS) || (SANITIZER_IOS && defined(__arm__))
# define ASAN_INTERCEPT__UNWIND_SJLJ_RAISEEXCEPTION 1
# else
diff --git a/libsanitizer/asan/asan_mapping.h b/libsanitizer/asan/asan_mapping.h
index 09be904270c..41fb49ee46d 100644
--- a/libsanitizer/asan/asan_mapping.h
+++ b/libsanitizer/asan/asan_mapping.h
@@ -163,7 +163,7 @@ static const u64 kDefaultShort64bitShadowOffset =
static const u64 kAArch64_ShadowOffset64 = 1ULL << 36;
static const u64 kMIPS32_ShadowOffset32 = 0x0aaa0000;
static const u64 kMIPS64_ShadowOffset64 = 1ULL << 37;
-static const u64 kPPC64_ShadowOffset64 = 1ULL << 41;
+static const u64 kPPC64_ShadowOffset64 = 1ULL << 44;
static const u64 kSystemZ_ShadowOffset64 = 1ULL << 52;
static const u64 kSPARC64_ShadowOffset64 = 1ULL << 43; // 0x80000000000
static const u64 kFreeBSD_ShadowOffset32 = 1ULL << 30; // 0x40000000
diff --git a/libsanitizer/asan/asan_report.cpp b/libsanitizer/asan/asan_report.cpp
index 2e6ce436d03..99e8678aa78 100644
--- a/libsanitizer/asan/asan_report.cpp
+++ b/libsanitizer/asan/asan_report.cpp
@@ -160,6 +160,9 @@ class ScopedInErrorReport {
BlockingMutexLock l(&error_message_buf_mutex);
internal_memcpy(buffer_copy.data(),
error_message_buffer, kErrorMessageBufferSize);
+ // Clear error_message_buffer so that if we find other errors
+ // we don't re-log this error.
+ error_message_buffer_pos = 0;
}
LogFullErrorReport(buffer_copy.data());
diff --git a/libsanitizer/asan/asan_thread.cpp b/libsanitizer/asan/asan_thread.cpp
index 6734d9a1668..f0df8bd4b37 100644
--- a/libsanitizer/asan/asan_thread.cpp
+++ b/libsanitizer/asan/asan_thread.cpp
@@ -480,6 +480,8 @@ bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end,
return true;
}
+void GetAllThreadAllocatorCachesLocked(InternalMmapVector<uptr> *caches) {}
+
void ForEachExtraStackRange(tid_t os_id, RangeIteratorCallback callback,
void *arg) {
__asan::AsanThread *t = __asan::GetAsanThreadByOsIDLocked(os_id);
diff --git a/libsanitizer/include/sanitizer/linux_syscall_hooks.h b/libsanitizer/include/sanitizer/linux_syscall_hooks.h
index a1794b71af5..56eae3d40f9 100644
--- a/libsanitizer/include/sanitizer/linux_syscall_hooks.h
+++ b/libsanitizer/include/sanitizer/linux_syscall_hooks.h
@@ -1845,6 +1845,10 @@
#define __sanitizer_syscall_post_rt_sigaction(res, signum, act, oldact, sz) \
__sanitizer_syscall_post_impl_rt_sigaction(res, (long)signum, (long)act, \
(long)oldact, (long)sz)
+#define __sanitizer_syscall_pre_sigaltstack(ss, oss) \
+ __sanitizer_syscall_pre_impl_sigaltstack((long)ss, (long)oss)
+#define __sanitizer_syscall_post_sigaltstack(res, ss, oss) \
+ __sanitizer_syscall_post_impl_sigaltstack(res, (long)ss, (long)oss)
// And now a few syscalls we don't handle yet.
#define __sanitizer_syscall_pre_afs_syscall(...)
@@ -1912,7 +1916,6 @@
#define __sanitizer_syscall_pre_setreuid32(...)
#define __sanitizer_syscall_pre_set_thread_area(...)
#define __sanitizer_syscall_pre_setuid32(...)
-#define __sanitizer_syscall_pre_sigaltstack(...)
#define __sanitizer_syscall_pre_sigreturn(...)
#define __sanitizer_syscall_pre_sigsuspend(...)
#define __sanitizer_syscall_pre_stty(...)
@@ -1992,7 +1995,6 @@
#define __sanitizer_syscall_post_setreuid32(res, ...)
#define __sanitizer_syscall_post_set_thread_area(res, ...)
#define __sanitizer_syscall_post_setuid32(res, ...)
-#define __sanitizer_syscall_post_sigaltstack(res, ...)
#define __sanitizer_syscall_post_sigreturn(res, ...)
#define __sanitizer_syscall_post_sigsuspend(res, ...)
#define __sanitizer_syscall_post_stty(res, ...)
@@ -3075,6 +3077,8 @@ void __sanitizer_syscall_pre_impl_rt_sigaction(long signum, long act,
long oldact, long sz);
void __sanitizer_syscall_post_impl_rt_sigaction(long res, long signum, long act,
long oldact, long sz);
+void __sanitizer_syscall_pre_impl_sigaltstack(long ss, long oss);
+void __sanitizer_syscall_post_impl_sigaltstack(long res, long ss, long oss);
#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/libsanitizer/include/sanitizer/netbsd_syscall_hooks.h b/libsanitizer/include/sanitizer/netbsd_syscall_hooks.h
index 174b4bf06de..370da0ea72e 100644
--- a/libsanitizer/include/sanitizer/netbsd_syscall_hooks.h
+++ b/libsanitizer/include/sanitizer/netbsd_syscall_hooks.h
@@ -20,7 +20,7 @@
// DO NOT EDIT! THIS FILE HAS BEEN GENERATED!
//
// Generated with: generate_netbsd_syscalls.awk
-// Generated date: 2019-11-01
+// Generated date: 2019-12-24
// Generated from: syscalls.master,v 1.296 2019/09/22 22:59:39 christos Exp
//
//===----------------------------------------------------------------------===//
diff --git a/libsanitizer/include/sanitizer/tsan_interface.h b/libsanitizer/include/sanitizer/tsan_interface.h
index 011b23350ca..96b8ad58541 100644
--- a/libsanitizer/include/sanitizer/tsan_interface.h
+++ b/libsanitizer/include/sanitizer/tsan_interface.h
@@ -38,34 +38,34 @@ void __tsan_release(void *addr);
// Mutex has static storage duration and no-op constructor and destructor.
// This effectively makes tsan ignore destroy annotation.
-const unsigned __tsan_mutex_linker_init = 1 << 0;
+static const unsigned __tsan_mutex_linker_init = 1 << 0;
// Mutex is write reentrant.
-const unsigned __tsan_mutex_write_reentrant = 1 << 1;
+static const unsigned __tsan_mutex_write_reentrant = 1 << 1;
// Mutex is read reentrant.
-const unsigned __tsan_mutex_read_reentrant = 1 << 2;
+static const unsigned __tsan_mutex_read_reentrant = 1 << 2;
// Mutex does not have static storage duration, and must not be used after
// its destructor runs. The opposite of __tsan_mutex_linker_init.
// If this flag is passed to __tsan_mutex_destroy, then the destruction
// is ignored unless this flag was previously set on the mutex.
-const unsigned __tsan_mutex_not_static = 1 << 8;
+static const unsigned __tsan_mutex_not_static = 1 << 8;
// Mutex operation flags:
// Denotes read lock operation.
-const unsigned __tsan_mutex_read_lock = 1 << 3;
+static const unsigned __tsan_mutex_read_lock = 1 << 3;
// Denotes try lock operation.
-const unsigned __tsan_mutex_try_lock = 1 << 4;
+static const unsigned __tsan_mutex_try_lock = 1 << 4;
// Denotes that a try lock operation has failed to acquire the mutex.
-const unsigned __tsan_mutex_try_lock_failed = 1 << 5;
+static const unsigned __tsan_mutex_try_lock_failed = 1 << 5;
// Denotes that the lock operation acquires multiple recursion levels.
// Number of levels is passed in recursion parameter.
// This is useful for annotation of e.g. Java builtin monitors,
// for which wait operation releases all recursive acquisitions of the mutex.
-const unsigned __tsan_mutex_recursive_lock = 1 << 6;
+static const unsigned __tsan_mutex_recursive_lock = 1 << 6;
// Denotes that the unlock operation releases all recursion levels.
// Number of released levels is returned and later must be passed to
// the corresponding __tsan_mutex_post_lock annotation.
-const unsigned __tsan_mutex_recursive_unlock = 1 << 7;
+static const unsigned __tsan_mutex_recursive_unlock = 1 << 7;
// Annotate creation of a mutex.
// Supported flags: mutex creation flags.
@@ -152,7 +152,7 @@ void __tsan_set_fiber_name(void *fiber, const char *name);
// Flags for __tsan_switch_to_fiber:
// Do not establish a happens-before relation between fibers
-const unsigned __tsan_switch_to_fiber_no_sync = 1 << 0;
+static const unsigned __tsan_switch_to_fiber_no_sync = 1 << 0;
#ifdef __cplusplus
} // extern "C"
diff --git a/libsanitizer/lsan/lsan.cpp b/libsanitizer/lsan/lsan.cpp
index 4ce03046ffb..80a6e2fa701 100644
--- a/libsanitizer/lsan/lsan.cpp
+++ b/libsanitizer/lsan/lsan.cpp
@@ -15,7 +15,6 @@
#include "sanitizer_common/sanitizer_flags.h"
#include "sanitizer_common/sanitizer_flag_parser.h"
-#include "sanitizer_common/sanitizer_stacktrace.h"
#include "lsan_allocator.h"
#include "lsan_common.h"
#include "lsan_thread.h"
@@ -87,17 +86,6 @@ static void InitializeFlags() {
__sanitizer_set_report_path(common_flags()->log_path);
}
-static void OnStackUnwind(const SignalContext &sig, const void *,
- BufferedStackTrace *stack) {
- stack->Unwind(StackTrace::GetNextInstructionPc(sig.pc), sig.bp, sig.context,
- common_flags()->fast_unwind_on_fatal);
-}
-
-static void LsanOnDeadlySignal(int signo, void *siginfo, void *context) {
- HandleDeadlySignal(siginfo, context, GetCurrentThread(), &OnStackUnwind,
- nullptr);
-}
-
extern "C" void __lsan_init() {
CHECK(!lsan_init_is_running);
if (lsan_inited)
@@ -114,10 +102,7 @@ extern "C" void __lsan_init() {
InitializeInterceptors();
InitializeThreadRegistry();
InstallDeadlySignalHandlers(LsanOnDeadlySignal);
- u32 tid = ThreadCreate(0, 0, true);
- CHECK_EQ(tid, 0);
- ThreadStart(tid, GetTid());
- SetCurrentThread(tid);
+ InitializeMainThread();
if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit)
Atexit(DoLeakCheck);
diff --git a/libsanitizer/lsan/lsan.h b/libsanitizer/lsan/lsan.h
index 9904ada4bb3..1e82ad72f00 100644
--- a/libsanitizer/lsan/lsan.h
+++ b/libsanitizer/lsan/lsan.h
@@ -12,6 +12,11 @@
//===----------------------------------------------------------------------===//
#include "lsan_thread.h"
+#if SANITIZER_POSIX
+#include "lsan_posix.h"
+#elif SANITIZER_FUCHSIA
+#include "lsan_fuchsia.h"
+#endif
#include "sanitizer_common/sanitizer_flags.h"
#include "sanitizer_common/sanitizer_stacktrace.h"
@@ -33,6 +38,7 @@ namespace __lsan {
void InitializeInterceptors();
void ReplaceSystemMalloc();
+void LsanOnDeadlySignal(int signo, void *siginfo, void *context);
#define ENSURE_LSAN_INITED do { \
CHECK(!lsan_init_is_running); \
diff --git a/libsanitizer/lsan/lsan_allocator.h b/libsanitizer/lsan/lsan_allocator.h
index e1397099767..bda9d8cdf74 100644
--- a/libsanitizer/lsan/lsan_allocator.h
+++ b/libsanitizer/lsan/lsan_allocator.h
@@ -66,7 +66,10 @@ template <typename AddressSpaceView>
using PrimaryAllocatorASVT = SizeClassAllocator32<AP32<AddressSpaceView>>;
using PrimaryAllocator = PrimaryAllocatorASVT<LocalAddressSpaceView>;
#elif defined(__x86_64__) || defined(__powerpc64__)
-# if defined(__powerpc64__)
+# if SANITIZER_FUCHSIA
+const uptr kAllocatorSpace = ~(uptr)0;
+const uptr kAllocatorSize = 0x40000000000ULL; // 4T.
+# elif defined(__powerpc64__)
const uptr kAllocatorSpace = 0xa0000000000ULL;
const uptr kAllocatorSize = 0x20000000000ULL; // 2T.
# else
diff --git a/libsanitizer/lsan/lsan_common.cpp b/libsanitizer/lsan/lsan_common.cpp
index 9ff9f4c5d1c..32ea4e88003 100644
--- a/libsanitizer/lsan/lsan_common.cpp
+++ b/libsanitizer/lsan/lsan_common.cpp
@@ -211,6 +211,13 @@ void ForEachExtraStackRangeCb(uptr begin, uptr end, void* arg) {
ScanRangeForPointers(begin, end, frontier, "FAKE STACK", kReachable);
}
+#if SANITIZER_FUCHSIA
+
+// Fuchsia handles all threads together with its own callback.
+static void ProcessThreads(SuspendedThreadsList const &, Frontier *) {}
+
+#else
+
// Scans thread data (stacks and TLS) for heap pointers.
static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
Frontier *frontier) {
@@ -308,6 +315,8 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
}
}
+#endif // SANITIZER_FUCHSIA
+
void ScanRootRegion(Frontier *frontier, const RootRegion &root_region,
uptr region_begin, uptr region_end, bool is_readable) {
uptr intersection_begin = Max(root_region.begin, region_begin);
@@ -443,25 +452,23 @@ void ProcessPC(Frontier *frontier) {
}
// Sets the appropriate tag on each chunk.
-static void ClassifyAllChunks(SuspendedThreadsList const &suspended_threads) {
- // Holds the flood fill frontier.
- Frontier frontier;
-
- ForEachChunk(CollectIgnoredCb, &frontier);
- ProcessGlobalRegions(&frontier);
- ProcessThreads(suspended_threads, &frontier);
- ProcessRootRegions(&frontier);
- FloodFillTag(&frontier, kReachable);
+static void ClassifyAllChunks(SuspendedThreadsList const &suspended_threads,
+ Frontier *frontier) {
+ ForEachChunk(CollectIgnoredCb, frontier);
+ ProcessGlobalRegions(frontier);
+ ProcessThreads(suspended_threads, frontier);
+ ProcessRootRegions(frontier);
+ FloodFillTag(frontier, kReachable);
- CHECK_EQ(0, frontier.size());
- ProcessPC(&frontier);
+ CHECK_EQ(0, frontier->size());
+ ProcessPC(frontier);
// 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.
LOG_POINTERS("Processing platform-specific allocations.\n");
- ProcessPlatformSpecificAllocations(&frontier);
- FloodFillTag(&frontier, kReachable);
+ ProcessPlatformSpecificAllocations(frontier);
+ FloodFillTag(frontier, kReachable);
// Iterate over leaked chunks and mark those that are reachable from other
// leaked chunks.
@@ -521,11 +528,6 @@ static void PrintMatchedSuppressions() {
Printf("%s\n\n", line);
}
-struct CheckForLeaksParam {
- bool success;
- LeakReport leak_report;
-};
-
static void ReportIfNotSuspended(ThreadContextBase *tctx, void *arg) {
const InternalMmapVector<tid_t> &suspended_threads =
*(const InternalMmapVector<tid_t> *)arg;
@@ -538,6 +540,14 @@ static void ReportIfNotSuspended(ThreadContextBase *tctx, void *arg) {
}
}
+#if SANITIZER_FUCHSIA
+
+// Fuchsia provides a libc interface that guarantees all threads are
+// covered, and SuspendedThreadList is never really used.
+static void ReportUnsuspendedThreads(const SuspendedThreadsList &) {}
+
+#else // !SANITIZER_FUCHSIA
+
static void ReportUnsuspendedThreads(
const SuspendedThreadsList &suspended_threads) {
InternalMmapVector<tid_t> threads(suspended_threads.ThreadCount());
@@ -550,13 +560,15 @@ static void ReportUnsuspendedThreads(
&ReportIfNotSuspended, &threads);
}
+#endif // !SANITIZER_FUCHSIA
+
static void CheckForLeaksCallback(const SuspendedThreadsList &suspended_threads,
void *arg) {
CheckForLeaksParam *param = reinterpret_cast<CheckForLeaksParam *>(arg);
CHECK(param);
CHECK(!param->success);
ReportUnsuspendedThreads(suspended_threads);
- ClassifyAllChunks(suspended_threads);
+ ClassifyAllChunks(suspended_threads, ¶m->frontier);
ForEachChunk(CollectLeaksCb, ¶m->leak_report);
// Clean up for subsequent leak checks. This assumes we did not overwrite any
// kIgnored tags.
@@ -569,7 +581,6 @@ static bool CheckForLeaks() {
return false;
EnsureMainThreadIDIsCorrect();
CheckForLeaksParam param;
- param.success = false;
LockStuffAndStopTheWorld(CheckForLeaksCallback, ¶m);
if (!param.success) {
diff --git a/libsanitizer/lsan/lsan_common.h b/libsanitizer/lsan/lsan_common.h
index d24abe31b71..6252d52c197 100644
--- a/libsanitizer/lsan/lsan_common.h
+++ b/libsanitizer/lsan/lsan_common.h
@@ -40,7 +40,7 @@
#elif defined(__arm__) && \
SANITIZER_LINUX && !SANITIZER_ANDROID
#define CAN_SANITIZE_LEAKS 1
-#elif SANITIZER_NETBSD
+#elif SANITIZER_NETBSD || SANITIZER_FUCHSIA
#define CAN_SANITIZE_LEAKS 1
#else
#define CAN_SANITIZE_LEAKS 0
@@ -126,12 +126,24 @@ struct RootRegion {
uptr size;
};
+// LockStuffAndStopTheWorld can start to use Scan* calls to collect into
+// this Frontier vector before the StopTheWorldCallback actually runs.
+// This is used when the OS has a unified callback API for suspending
+// threads and enumerating roots.
+struct CheckForLeaksParam {
+ Frontier frontier;
+ LeakReport leak_report;
+ bool success = false;
+};
+
InternalMmapVector<RootRegion> const *GetRootRegions();
void ScanRootRegion(Frontier *frontier, RootRegion const ®ion,
uptr region_begin, uptr region_end, bool is_readable);
+void ForEachExtraStackRangeCb(uptr begin, uptr end, void* arg);
// Run stoptheworld while holding any platform-specific locks, as well as the
// allocator and thread registry locks.
-void LockStuffAndStopTheWorld(StopTheWorldCallback callback, void* argument);
+void LockStuffAndStopTheWorld(StopTheWorldCallback callback,
+ CheckForLeaksParam* argument);
void ScanRangeForPointers(uptr begin, uptr end,
Frontier *frontier,
@@ -211,6 +223,7 @@ ThreadRegistry *GetThreadRegistryLocked();
bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end,
uptr *tls_begin, uptr *tls_end, uptr *cache_begin,
uptr *cache_end, DTLS **dtls);
+void GetAllThreadAllocatorCachesLocked(InternalMmapVector<uptr> *caches);
void ForEachExtraStackRange(tid_t os_id, RangeIteratorCallback callback,
void *arg);
// If called from the main thread, updates the main thread's TID in the thread
diff --git a/libsanitizer/lsan/lsan_common_fuchsia.cpp b/libsanitizer/lsan/lsan_common_fuchsia.cpp
new file mode 100644
index 00000000000..caedbf15596
--- /dev/null
+++ b/libsanitizer/lsan/lsan_common_fuchsia.cpp
@@ -0,0 +1,166 @@
+//=-- lsan_common_fuchsia.cpp --------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===---------------------------------------------------------------------===//
+//
+// This file is a part of LeakSanitizer.
+// Implementation of common leak checking functionality. Fuchsia-specific code.
+//
+//===---------------------------------------------------------------------===//
+
+#include "lsan_common.h"
+#include "sanitizer_common/sanitizer_platform.h"
+
+#if CAN_SANITIZE_LEAKS && SANITIZER_FUCHSIA
+#include <zircon/sanitizer.h>
+
+#include "lsan_allocator.h"
+#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_thread_registry.h"
+
+// Ensure that the Zircon system ABI is linked in.
+#pragma comment(lib, "zircon")
+
+namespace __lsan {
+
+void InitializePlatformSpecificModules() {}
+
+LoadedModule *GetLinker() { return nullptr; }
+
+__attribute__((tls_model("initial-exec"))) THREADLOCAL int disable_counter;
+bool DisabledInThisThread() { return disable_counter > 0; }
+void DisableInThisThread() { disable_counter++; }
+void EnableInThisThread() {
+ if (disable_counter == 0) {
+ DisableCounterUnderflow();
+ }
+ disable_counter--;
+}
+
+// There is nothing left to do after the globals callbacks.
+void ProcessGlobalRegions(Frontier *frontier) {}
+
+// Nothing to do here.
+void ProcessPlatformSpecificAllocations(Frontier *frontier) {}
+
+// On Fuchsia, we can intercept _Exit gracefully, and return a failing exit
+// code if required at that point. Calling Die() here is undefined
+// behavior and causes rare race conditions.
+void HandleLeaks() {}
+
+int ExitHook(int status) {
+ return status == 0 && HasReportedLeaks() ? common_flags()->exitcode : status;
+}
+
+void LockStuffAndStopTheWorld(StopTheWorldCallback callback,
+ CheckForLeaksParam *argument) {
+ LockThreadRegistry();
+ LockAllocator();
+
+ struct Params {
+ InternalMmapVector<uptr> allocator_caches;
+ StopTheWorldCallback callback;
+ CheckForLeaksParam *argument;
+ } params = {{}, callback, argument};
+
+ // Callback from libc for globals (data/bss modulo relro), when enabled.
+ auto globals = +[](void *chunk, size_t size, void *data) {
+ auto params = static_cast<const Params *>(data);
+ uptr begin = reinterpret_cast<uptr>(chunk);
+ uptr end = begin + size;
+ ScanGlobalRange(begin, end, ¶ms->argument->frontier);
+ };
+
+ // Callback from libc for thread stacks.
+ auto stacks = +[](void *chunk, size_t size, void *data) {
+ auto params = static_cast<const Params *>(data);
+ uptr begin = reinterpret_cast<uptr>(chunk);
+ uptr end = begin + size;
+ ScanRangeForPointers(begin, end, ¶ms->argument->frontier, "STACK",
+ kReachable);
+ };
+
+ // Callback from libc for thread registers.
+ auto registers = +[](void *chunk, size_t size, void *data) {
+ auto params = static_cast<const Params *>(data);
+ uptr begin = reinterpret_cast<uptr>(chunk);
+ uptr end = begin + size;
+ ScanRangeForPointers(begin, end, ¶ms->argument->frontier, "REGISTERS",
+ kReachable);
+ };
+
+ if (flags()->use_tls) {
+ // Collect the allocator cache range from each thread so these
+ // can all be excluded from the reported TLS ranges.
+ GetAllThreadAllocatorCachesLocked(¶ms.allocator_caches);
+ __sanitizer::Sort(params.allocator_caches.data(),
+ params.allocator_caches.size());
+ }
+
+ // Callback from libc for TLS regions. This includes thread_local
+ // variables as well as C11 tss_set and POSIX pthread_setspecific.
+ auto tls = +[](void *chunk, size_t size, void *data) {
+ auto params = static_cast<const Params *>(data);
+ uptr begin = reinterpret_cast<uptr>(chunk);
+ uptr end = begin + size;
+ auto i = __sanitizer::InternalLowerBound(params->allocator_caches, 0,
+ params->allocator_caches.size(),
+ begin, CompareLess<uptr>());
+ if (i < params->allocator_caches.size() &&
+ params->allocator_caches[i] >= begin &&
+ end - params->allocator_caches[i] <= sizeof(AllocatorCache)) {
+ // Split the range in two and omit the allocator cache within.
+ ScanRangeForPointers(begin, params->allocator_caches[i],
+ ¶ms->argument->frontier, "TLS", kReachable);
+ uptr begin2 = params->allocator_caches[i] + sizeof(AllocatorCache);
+ ScanRangeForPointers(begin2, end, ¶ms->argument->frontier, "TLS",
+ kReachable);
+ } else {
+ ScanRangeForPointers(begin, end, ¶ms->argument->frontier, "TLS",
+ kReachable);
+ }
+ };
+
+ // This stops the world and then makes callbacks for various memory regions.
+ // The final callback is the last thing before the world starts up again.
+ __sanitizer_memory_snapshot(
+ flags()->use_globals ? globals : nullptr,
+ flags()->use_stacks ? stacks : nullptr,
+ flags()->use_registers ? registers : nullptr,
+ flags()->use_tls ? tls : nullptr,
+ [](zx_status_t, void *data) {
+ auto params = static_cast<const Params *>(data);
+
+ // We don't use the thread registry at all for enumerating the threads
+ // and their stacks, registers, and TLS regions. So use it separately
+ // just for the allocator cache, and to call ForEachExtraStackRange,
+ // which ASan needs.
+ if (flags()->use_stacks) {
+ GetThreadRegistryLocked()->RunCallbackForEachThreadLocked(
+ [](ThreadContextBase *tctx, void *arg) {
+ ForEachExtraStackRange(tctx->os_id, ForEachExtraStackRangeCb,
+ arg);
+ },
+ ¶ms->argument->frontier);
+ }
+
+ params->callback({}, params->argument);
+ },
+ ¶ms);
+
+ UnlockAllocator();
+ UnlockThreadRegistry();
+}
+
+} // namespace __lsan
+
+// This is declared (in extern "C") by <zircon/sanitizer.h>.
+// _Exit calls this directly to intercept and change the status value.
+int __sanitizer_process_exit_hook(int status) {
+ return __lsan::ExitHook(status);
+}
+
+#endif
diff --git a/libsanitizer/lsan/lsan_common_linux.cpp b/libsanitizer/lsan/lsan_common_linux.cpp
index ea1a4a2f569..c97ef31593d 100644
--- a/libsanitizer/lsan/lsan_common_linux.cpp
+++ b/libsanitizer/lsan/lsan_common_linux.cpp
@@ -134,7 +134,8 @@ static int LockStuffAndStopTheWorldCallback(struct dl_phdr_info *info,
// while holding the libdl lock in the parent thread, we can safely reenter it
// in the tracer. The solution is to run stoptheworld from a dl_iterate_phdr()
// callback in the parent thread.
-void LockStuffAndStopTheWorld(StopTheWorldCallback callback, void *argument) {
+void LockStuffAndStopTheWorld(StopTheWorldCallback callback,
+ CheckForLeaksParam *argument) {
DoStopTheWorldParam param = {callback, argument};
dl_iterate_phdr(LockStuffAndStopTheWorldCallback, ¶m);
}
diff --git a/libsanitizer/lsan/lsan_common_mac.cpp b/libsanitizer/lsan/lsan_common_mac.cpp
index c1804e93c11..8516a176eb4 100644
--- a/libsanitizer/lsan/lsan_common_mac.cpp
+++ b/libsanitizer/lsan/lsan_common_mac.cpp
@@ -193,7 +193,8 @@ void ProcessPlatformSpecificAllocations(Frontier *frontier) {
// causes rare race conditions.
void HandleLeaks() {}
-void LockStuffAndStopTheWorld(StopTheWorldCallback callback, void *argument) {
+void LockStuffAndStopTheWorld(StopTheWorldCallback callback,
+ CheckForLeaksParam *argument) {
LockThreadRegistry();
LockAllocator();
StopTheWorld(callback, argument);
diff --git a/libsanitizer/lsan/lsan_fuchsia.cpp b/libsanitizer/lsan/lsan_fuchsia.cpp
new file mode 100644
index 00000000000..40e65c6fb72
--- /dev/null
+++ b/libsanitizer/lsan/lsan_fuchsia.cpp
@@ -0,0 +1,123 @@
+//=-- lsan_fuchsia.cpp ---------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===---------------------------------------------------------------------===//
+//
+// This file is a part of LeakSanitizer.
+// Standalone LSan RTL code specific to Fuchsia.
+//
+//===---------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_platform.h"
+
+#if SANITIZER_FUCHSIA
+#include <zircon/sanitizer.h>
+
+#include "lsan.h"
+#include "lsan_allocator.h"
+
+using namespace __lsan;
+
+namespace __lsan {
+
+void LsanOnDeadlySignal(int signo, void *siginfo, void *context) {}
+
+ThreadContext::ThreadContext(int tid) : ThreadContextLsanBase(tid) {}
+
+struct OnCreatedArgs {
+ uptr stack_begin, stack_end;
+};
+
+// On Fuchsia, the stack bounds of a new thread are available before
+// the thread itself has started running.
+void ThreadContext::OnCreated(void *arg) {
+ // Stack bounds passed through from __sanitizer_before_thread_create_hook
+ // or InitializeMainThread.
+ auto args = reinterpret_cast<const OnCreatedArgs *>(arg);
+ stack_begin_ = args->stack_begin;
+ stack_end_ = args->stack_end;
+}
+
+struct OnStartedArgs {
+ uptr cache_begin, cache_end;
+};
+
+void ThreadContext::OnStarted(void *arg) {
+ auto args = reinterpret_cast<const OnStartedArgs *>(arg);
+ cache_begin_ = args->cache_begin;
+ cache_end_ = args->cache_end;
+}
+
+void ThreadStart(u32 tid) {
+ OnStartedArgs args;
+ GetAllocatorCacheRange(&args.cache_begin, &args.cache_end);
+ CHECK_EQ(args.cache_end - args.cache_begin, sizeof(AllocatorCache));
+ ThreadContextLsanBase::ThreadStart(tid, GetTid(), ThreadType::Regular, &args);
+}
+
+void InitializeMainThread() {
+ OnCreatedArgs args;
+ __sanitizer::GetThreadStackTopAndBottom(true, &args.stack_end,
+ &args.stack_begin);
+ u32 tid = ThreadCreate(0, GetThreadSelf(), true, &args);
+ CHECK_EQ(tid, 0);
+ ThreadStart(tid);
+}
+
+void GetAllThreadAllocatorCachesLocked(InternalMmapVector<uptr> *caches) {
+ GetThreadRegistryLocked()->RunCallbackForEachThreadLocked(
+ [](ThreadContextBase *tctx, void *arg) {
+ auto ctx = static_cast<ThreadContext *>(tctx);
+ static_cast<decltype(caches)>(arg)->push_back(ctx->cache_begin());
+ },
+ caches);
+}
+
+} // namespace __lsan
+
+// These are declared (in extern "C") by <zircon/sanitizer.h>.
+// The system runtime will call our definitions directly.
+
+// This is called before each thread creation is attempted. So, in
+// its first call, the calling thread is the initial and sole thread.
+void *__sanitizer_before_thread_create_hook(thrd_t thread, bool detached,
+ const char *name, void *stack_base,
+ size_t stack_size) {
+ uptr user_id = reinterpret_cast<uptr>(thread);
+ ENSURE_LSAN_INITED;
+ EnsureMainThreadIDIsCorrect();
+ OnCreatedArgs args;
+ args.stack_begin = reinterpret_cast<uptr>(stack_base);
+ args.stack_end = args.stack_begin + stack_size;
+ u32 parent_tid = GetCurrentThread();
+ u32 tid = ThreadCreate(parent_tid, user_id, detached, &args);
+ return reinterpret_cast<void *>(static_cast<uptr>(tid));
+}
+
+// This is called after creating a new thread (in the creating thread),
+// with the pointer returned by __sanitizer_before_thread_create_hook (above).
+void __sanitizer_thread_create_hook(void *hook, thrd_t thread, int error) {
+ u32 tid = static_cast<u32>(reinterpret_cast<uptr>(hook));
+ // On success, there is nothing to do here.
+ if (error != thrd_success) {
+ // Clean up the thread registry for the thread creation that didn't happen.
+ GetThreadRegistryLocked()->FinishThread(tid);
+ }
+}
+
+// This is called in the newly-created thread before it runs anything else,
+// with the pointer returned by __sanitizer_before_thread_create_hook (above).
+void __sanitizer_thread_start_hook(void *hook, thrd_t self) {
+ u32 tid = static_cast<u32>(reinterpret_cast<uptr>(hook));
+ ThreadStart(tid);
+}
+
+// Each thread runs this just before it exits,
+// with the pointer returned by BeforeThreadCreateHook (above).
+// All per-thread destructors have already been called.
+void __sanitizer_thread_exit_hook(void *hook, thrd_t self) { ThreadFinish(); }
+
+#endif // SANITIZER_FUCHSIA
diff --git a/libsanitizer/lsan/lsan_fuchsia.h b/libsanitizer/lsan/lsan_fuchsia.h
new file mode 100644
index 00000000000..65d20ea2114
--- /dev/null
+++ b/libsanitizer/lsan/lsan_fuchsia.h
@@ -0,0 +1,35 @@
+//=-- lsan_fuchsia.h ---------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===---------------------------------------------------------------------===//
+//
+// This file is a part of LeakSanitizer.
+// Standalone LSan RTL code specific to Fuchsia.
+//
+//===---------------------------------------------------------------------===//
+
+#ifndef LSAN_FUCHSIA_H
+#define LSAN_FUCHSIA_H
+
+#include "lsan_thread.h"
+#include "sanitizer_common/sanitizer_platform.h"
+
+#if !SANITIZER_FUCHSIA
+#error "lsan_fuchsia.h is used only on Fuchsia systems (SANITIZER_FUCHSIA)"
+#endif
+
+namespace __lsan {
+
+class ThreadContext : public ThreadContextLsanBase {
+ public:
+ explicit ThreadContext(int tid);
+ void OnCreated(void *arg) override;
+ void OnStarted(void *arg) override;
+};
+
+} // namespace __lsan
+
+#endif // LSAN_FUCHSIA_H
diff --git a/libsanitizer/lsan/lsan_interceptors.cpp b/libsanitizer/lsan/lsan_interceptors.cpp
index f642bb807bc..9ce9b78c5a5 100644
--- a/libsanitizer/lsan/lsan_interceptors.cpp
+++ b/libsanitizer/lsan/lsan_interceptors.cpp
@@ -22,7 +22,9 @@
#include "sanitizer_common/sanitizer_platform_interceptors.h"
#include "sanitizer_common/sanitizer_platform_limits_netbsd.h"
#include "sanitizer_common/sanitizer_platform_limits_posix.h"
+#if SANITIZER_POSIX
#include "sanitizer_common/sanitizer_posix.h"
+#endif
#include "sanitizer_common/sanitizer_tls_get_addr.h"
#include "lsan.h"
#include "lsan_allocator.h"
@@ -61,6 +63,9 @@ INTERCEPTOR(void, free, void *p) {
}
INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {
+ // This hack is not required for Fuchsia because there are no dlsym calls
+ // involved in setting up interceptors.
+#if !SANITIZER_FUCHSIA
if (lsan_init_is_running) {
// Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym.
const uptr kCallocPoolSize = 1024;
@@ -72,6 +77,7 @@ INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {
CHECK(allocated < kCallocPoolSize);
return mem;
}
+#endif // !SANITIZER_FUCHSIA
ENSURE_LSAN_INITED;
GET_STACK_TRACE_MALLOC;
return lsan_calloc(nmemb, size, stack);
@@ -100,7 +106,7 @@ INTERCEPTOR(void*, valloc, uptr size) {
GET_STACK_TRACE_MALLOC;
return lsan_valloc(size, stack);
}
-#endif
+#endif // !SANITIZER_MAC
#if SANITIZER_INTERCEPT_MEMALIGN
INTERCEPTOR(void*, memalign, uptr alignment, uptr size) {
@@ -307,7 +313,7 @@ INTERCEPTOR(void, _ZdaPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&)
///// Thread initialization and finalization. /////
-#if !SANITIZER_NETBSD && !SANITIZER_FREEBSD
+#if !SANITIZER_NETBSD && !SANITIZER_FREEBSD && !SANITIZER_FUCHSIA
static unsigned g_thread_finalize_key;
static void thread_finalize(void *v) {
@@ -394,6 +400,8 @@ INTERCEPTOR(char *, strerror, int errnum) {
#define LSAN_MAYBE_INTERCEPT_STRERROR
#endif
+#if SANITIZER_POSIX
+
struct ThreadParam {
void *(*callback)(void *arg);
void *param;
@@ -416,7 +424,6 @@ extern "C" void *__lsan_thread_start_func(void *arg) {
int tid = 0;
while ((tid = atomic_load(&p->tid, memory_order_acquire)) == 0)
internal_sched_yield();
- SetCurrentThread(tid);
ThreadStart(tid, GetTid());
atomic_store(&p->tid, 0, memory_order_release);
return callback(param);
@@ -477,9 +484,13 @@ INTERCEPTOR(void, _exit, int status) {
#define COMMON_INTERCEPT_FUNCTION(name) INTERCEPT_FUNCTION(name)
#include "sanitizer_common/sanitizer_signal_interceptors.inc"
+#endif // SANITIZER_POSIX
+
namespace __lsan {
void InitializeInterceptors() {
+ // Fuchsia doesn't use interceptors that require any setup.
+#if !SANITIZER_FUCHSIA
InitializeSignalInterceptors();
INTERCEPT_FUNCTION(malloc);
@@ -515,6 +526,8 @@ void InitializeInterceptors() {
Die();
}
#endif
+
+#endif // !SANITIZER_FUCHSIA
}
} // namespace __lsan
diff --git a/libsanitizer/lsan/lsan_linux.cpp b/libsanitizer/lsan/lsan_linux.cpp
index 14a42b75d2a..47c2f21b5a6 100644
--- a/libsanitizer/lsan/lsan_linux.cpp
+++ b/libsanitizer/lsan/lsan_linux.cpp
@@ -6,13 +6,13 @@
//
//===----------------------------------------------------------------------===//
//
-// This file is a part of LeakSanitizer. Linux/NetBSD-specific code.
+// This file is a part of LeakSanitizer. Linux/NetBSD/Fuchsia-specific code.
//
//===----------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_platform.h"
-#if SANITIZER_LINUX || SANITIZER_NETBSD
+#if SANITIZER_LINUX || SANITIZER_NETBSD || SANITIZER_FUCHSIA
#include "lsan_allocator.h"
@@ -29,4 +29,4 @@ void ReplaceSystemMalloc() {}
} // namespace __lsan
-#endif // SANITIZER_LINUX || SANITIZER_NETBSD
+#endif // SANITIZER_LINUX || SANITIZER_NETBSD || SANITIZER_FUCHSIA
diff --git a/libsanitizer/lsan/lsan_posix.cpp b/libsanitizer/lsan/lsan_posix.cpp
new file mode 100644
index 00000000000..8e05915dd1b
--- /dev/null
+++ b/libsanitizer/lsan/lsan_posix.cpp
@@ -0,0 +1,96 @@
+//=-- lsan_posix.cpp -----------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===---------------------------------------------------------------------===//
+//
+// This file is a part of LeakSanitizer.
+// Standalone LSan RTL code common to POSIX-like systems.
+//
+//===---------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_platform.h"
+
+#if SANITIZER_POSIX
+#include "lsan.h"
+#include "lsan_allocator.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
+#include "sanitizer_common/sanitizer_tls_get_addr.h"
+
+namespace __lsan {
+
+ThreadContext::ThreadContext(int tid) : ThreadContextLsanBase(tid) {}
+
+struct OnStartedArgs {
+ uptr stack_begin;
+ uptr stack_end;
+ uptr cache_begin;
+ uptr cache_end;
+ uptr tls_begin;
+ uptr tls_end;
+ DTLS *dtls;
+};
+
+void ThreadContext::OnStarted(void *arg) {
+ auto args = reinterpret_cast<const OnStartedArgs *>(arg);
+ stack_begin_ = args->stack_begin;
+ stack_end_ = args->stack_end;
+ tls_begin_ = args->tls_begin;
+ tls_end_ = args->tls_end;
+ cache_begin_ = args->cache_begin;
+ cache_end_ = args->cache_end;
+ dtls_ = args->dtls;
+}
+
+void ThreadStart(u32 tid, tid_t os_id, ThreadType thread_type) {
+ OnStartedArgs args;
+ uptr stack_size = 0;
+ uptr tls_size = 0;
+ GetThreadStackAndTls(tid == 0, &args.stack_begin, &stack_size,
+ &args.tls_begin, &tls_size);
+ args.stack_end = args.stack_begin + stack_size;
+ args.tls_end = args.tls_begin + tls_size;
+ GetAllocatorCacheRange(&args.cache_begin, &args.cache_end);
+ args.dtls = DTLS_Get();
+ ThreadContextLsanBase::ThreadStart(tid, os_id, thread_type, &args);
+}
+
+bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end,
+ uptr *tls_begin, uptr *tls_end, uptr *cache_begin,
+ uptr *cache_end, DTLS **dtls) {
+ ThreadContext *context = static_cast<ThreadContext *>(
+ GetThreadRegistryLocked()->FindThreadContextByOsIDLocked(os_id));
+ if (!context)
+ return false;
+ *stack_begin = context->stack_begin();
+ *stack_end = context->stack_end();
+ *tls_begin = context->tls_begin();
+ *tls_end = context->tls_end();
+ *cache_begin = context->cache_begin();
+ *cache_end = context->cache_end();
+ *dtls = context->dtls();
+ return true;
+}
+
+void InitializeMainThread() {
+ u32 tid = ThreadCreate(0, 0, true);
+ CHECK_EQ(tid, 0);
+ ThreadStart(tid, GetTid());
+}
+
+static void OnStackUnwind(const SignalContext &sig, const void *,
+ BufferedStackTrace *stack) {
+ stack->Unwind(StackTrace::GetNextInstructionPc(sig.pc), sig.bp, sig.context,
+ common_flags()->fast_unwind_on_fatal);
+}
+
+void LsanOnDeadlySignal(int signo, void *siginfo, void *context) {
+ HandleDeadlySignal(siginfo, context, GetCurrentThread(), &OnStackUnwind,
+ nullptr);
+}
+
+} // namespace __lsan
+
+#endif // SANITIZER_POSIX
diff --git a/libsanitizer/lsan/lsan_posix.h b/libsanitizer/lsan/lsan_posix.h
new file mode 100644
index 00000000000..840e427c55e
--- /dev/null
+++ b/libsanitizer/lsan/lsan_posix.h
@@ -0,0 +1,49 @@
+//=-- lsan_posix.h -----------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===---------------------------------------------------------------------===//
+//
+// This file is a part of LeakSanitizer.
+// Standalone LSan RTL code common to POSIX-like systems.
+//
+//===---------------------------------------------------------------------===//
+
+#ifndef LSAN_POSIX_H
+#define LSAN_POSIX_H
+
+#include "lsan_thread.h"
+#include "sanitizer_common/sanitizer_platform.h"
+
+#if !SANITIZER_POSIX
+#error "lsan_posix.h is used only on POSIX-like systems (SANITIZER_POSIX)"
+#endif
+
+namespace __sanitizer {
+struct DTLS;
+}
+
+namespace __lsan {
+
+class ThreadContext : public ThreadContextLsanBase {
+ public:
+ explicit ThreadContext(int tid);
+ void OnStarted(void *arg) override;
+ uptr tls_begin() { return tls_begin_; }
+ uptr tls_end() { return tls_end_; }
+ DTLS *dtls() { return dtls_; }
+
+ private:
+ uptr tls_begin_ = 0;
+ uptr tls_end_ = 0;
+ DTLS *dtls_ = nullptr;
+};
+
+void ThreadStart(u32 tid, tid_t os_id,
+ ThreadType thread_type = ThreadType::Regular);
+
+} // namespace __lsan
+
+#endif // LSAN_POSIX_H
diff --git a/libsanitizer/lsan/lsan_thread.cpp b/libsanitizer/lsan/lsan_thread.cpp
index 84e7ce61b97..40bdc254bb6 100644
--- a/libsanitizer/lsan/lsan_thread.cpp
+++ b/libsanitizer/lsan/lsan_thread.cpp
@@ -13,12 +13,13 @@
#include "lsan_thread.h"
+#include "lsan.h"
+#include "lsan_allocator.h"
+#include "lsan_common.h"
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_placement_new.h"
#include "sanitizer_common/sanitizer_thread_registry.h"
#include "sanitizer_common/sanitizer_tls_get_addr.h"
-#include "lsan_allocator.h"
-#include "lsan_common.h"
namespace __lsan {
@@ -26,7 +27,7 @@ static ThreadRegistry *thread_registry;
static ThreadContextBase *CreateThreadContext(u32 tid) {
void *mem = MmapOrDie(sizeof(ThreadContext), "ThreadContext");
- return new(mem) ThreadContext(tid);
+ return new (mem) ThreadContext(tid);
}
static const uptr kMaxThreads = 1 << 13;
@@ -34,59 +35,26 @@ static const uptr kThreadQuarantineSize = 64;
void InitializeThreadRegistry() {
static ALIGNED(64) char thread_registry_placeholder[sizeof(ThreadRegistry)];
- thread_registry = new(thread_registry_placeholder)
- ThreadRegistry(CreateThreadContext, kMaxThreads, kThreadQuarantineSize);
+ thread_registry = new (thread_registry_placeholder)
+ ThreadRegistry(CreateThreadContext, kMaxThreads, kThreadQuarantineSize);
}
-ThreadContext::ThreadContext(int tid)
- : ThreadContextBase(tid),
- stack_begin_(0),
- stack_end_(0),
- cache_begin_(0),
- cache_end_(0),
- tls_begin_(0),
- tls_end_(0),
- dtls_(nullptr) {}
-
-struct OnStartedArgs {
- uptr stack_begin, stack_end,
- cache_begin, cache_end,
- tls_begin, tls_end;
- DTLS *dtls;
-};
-
-void ThreadContext::OnStarted(void *arg) {
- OnStartedArgs *args = reinterpret_cast<OnStartedArgs *>(arg);
- stack_begin_ = args->stack_begin;
- stack_end_ = args->stack_end;
- tls_begin_ = args->tls_begin;
- tls_end_ = args->tls_end;
- cache_begin_ = args->cache_begin;
- cache_end_ = args->cache_end;
- dtls_ = args->dtls;
-}
+ThreadContextLsanBase::ThreadContextLsanBase(int tid)
+ : ThreadContextBase(tid) {}
-void ThreadContext::OnFinished() {
+void ThreadContextLsanBase::OnFinished() {
AllocatorThreadFinish();
DTLS_Destroy();
}
-u32 ThreadCreate(u32 parent_tid, uptr user_id, bool detached) {
- return thread_registry->CreateThread(user_id, detached, parent_tid,
- /* arg */ nullptr);
+u32 ThreadCreate(u32 parent_tid, uptr user_id, bool detached, void *arg) {
+ return thread_registry->CreateThread(user_id, detached, parent_tid, arg);
}
-void ThreadStart(u32 tid, tid_t os_id, ThreadType thread_type) {
- OnStartedArgs args;
- uptr stack_size = 0;
- uptr tls_size = 0;
- GetThreadStackAndTls(tid == 0, &args.stack_begin, &stack_size,
- &args.tls_begin, &tls_size);
- args.stack_end = args.stack_begin + stack_size;
- args.tls_end = args.tls_begin + tls_size;
- GetAllocatorCacheRange(&args.cache_begin, &args.cache_end);
- args.dtls = DTLS_Get();
- thread_registry->StartThread(tid, os_id, thread_type, &args);
+void ThreadContextLsanBase::ThreadStart(u32 tid, tid_t os_id,
+ ThreadType thread_type, void *arg) {
+ thread_registry->StartThread(tid, os_id, thread_type, arg);
+ SetCurrentThread(tid);
}
void ThreadFinish() {
@@ -95,7 +63,8 @@ void ThreadFinish() {
}
ThreadContext *CurrentThreadContext() {
- if (!thread_registry) return nullptr;
+ if (!thread_registry)
+ return nullptr;
if (GetCurrentThread() == kInvalidTid)
return nullptr;
// No lock needed when getting current thread.
@@ -111,12 +80,12 @@ static bool FindThreadByUid(ThreadContextBase *tctx, void *arg) {
}
u32 ThreadTid(uptr uid) {
- return thread_registry->FindThread(FindThreadByUid, (void*)uid);
+ return thread_registry->FindThread(FindThreadByUid, (void *)uid);
}
void ThreadJoin(u32 tid) {
CHECK_NE(tid, kInvalidTid);
- thread_registry->JoinThread(tid, /* arg */nullptr);
+ thread_registry->JoinThread(tid, /* arg */ nullptr);
}
void EnsureMainThreadIDIsCorrect() {
@@ -126,37 +95,16 @@ void EnsureMainThreadIDIsCorrect() {
///// Interface to the common LSan module. /////
-bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end,
- uptr *tls_begin, uptr *tls_end, uptr *cache_begin,
- uptr *cache_end, DTLS **dtls) {
- ThreadContext *context = static_cast<ThreadContext *>(
- thread_registry->FindThreadContextByOsIDLocked(os_id));
- if (!context) return false;
- *stack_begin = context->stack_begin();
- *stack_end = context->stack_end();
- *tls_begin = context->tls_begin();
- *tls_end = context->tls_end();
- *cache_begin = context->cache_begin();
- *cache_end = context->cache_end();
- *dtls = context->dtls();
- return true;
-}
-
void ForEachExtraStackRange(tid_t os_id, RangeIteratorCallback callback,
- void *arg) {
-}
+ void *arg) {}
-void LockThreadRegistry() {
- thread_registry->Lock();
-}
+void LockThreadRegistry() { thread_registry->Lock(); }
-void UnlockThreadRegistry() {
- thread_registry->Unlock();
-}
+void UnlockThreadRegistry() { thread_registry->Unlock(); }
ThreadRegistry *GetThreadRegistryLocked() {
thread_registry->CheckLocked();
return thread_registry;
}
-} // namespace __lsan
+} // namespace __lsan
diff --git a/libsanitizer/lsan/lsan_thread.h b/libsanitizer/lsan/lsan_thread.h
index b869d066d9d..0ab1582de66 100644
--- a/libsanitizer/lsan/lsan_thread.h
+++ b/libsanitizer/lsan/lsan_thread.h
@@ -16,38 +16,36 @@
#include "sanitizer_common/sanitizer_thread_registry.h"
-namespace __sanitizer {
-struct DTLS;
-}
-
namespace __lsan {
-class ThreadContext : public ThreadContextBase {
+class ThreadContextLsanBase : public ThreadContextBase {
public:
- explicit ThreadContext(int tid);
- void OnStarted(void *arg) override;
+ explicit ThreadContextLsanBase(int tid);
void OnFinished() override;
uptr stack_begin() { return stack_begin_; }
uptr stack_end() { return stack_end_; }
- uptr tls_begin() { return tls_begin_; }
- uptr tls_end() { return tls_end_; }
uptr cache_begin() { return cache_begin_; }
uptr cache_end() { return cache_end_; }
- DTLS *dtls() { return dtls_; }
- private:
- uptr stack_begin_, stack_end_,
- cache_begin_, cache_end_,
- tls_begin_, tls_end_;
- DTLS *dtls_;
+ // The argument is passed on to the subclass's OnStarted member function.
+ static void ThreadStart(u32 tid, tid_t os_id, ThreadType thread_type,
+ void *onstarted_arg);
+
+ protected:
+ uptr stack_begin_ = 0;
+ uptr stack_end_ = 0;
+ uptr cache_begin_ = 0;
+ uptr cache_end_ = 0;
};
+// This subclass of ThreadContextLsanBase is declared in an OS-specific header.
+class ThreadContext;
+
void InitializeThreadRegistry();
+void InitializeMainThread();
-void ThreadStart(u32 tid, tid_t os_id,
- ThreadType thread_type = ThreadType::Regular);
+u32 ThreadCreate(u32 tid, uptr uid, bool detached, void *arg = nullptr);
void ThreadFinish();
-u32 ThreadCreate(u32 tid, uptr uid, bool detached);
void ThreadJoin(u32 tid);
u32 ThreadTid(uptr uid);
@@ -55,6 +53,7 @@ u32 GetCurrentThread();
void SetCurrentThread(u32 tid);
ThreadContext *CurrentThreadContext();
void EnsureMainThreadIDIsCorrect();
+
} // namespace __lsan
#endif // LSAN_THREAD_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator.cpp b/libsanitizer/sanitizer_common/sanitizer_allocator.cpp
index 8d07906cca0..ec77b9cbfee 100644
--- a/libsanitizer/sanitizer_common/sanitizer_allocator.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_allocator.cpp
@@ -25,7 +25,7 @@ const char *PrimaryAllocatorName = "SizeClassAllocator";
const char *SecondaryAllocatorName = "LargeMmapAllocator";
// ThreadSanitizer for Go uses libc malloc/free.
-#if SANITIZER_GO || defined(SANITIZER_USE_MALLOC)
+#if defined(SANITIZER_USE_MALLOC)
# if SANITIZER_LINUX && !SANITIZER_ANDROID
extern "C" void *__libc_malloc(uptr size);
# if !SANITIZER_GO
@@ -213,7 +213,7 @@ void *LowLevelAllocator::Allocate(uptr size) {
// Align allocation size.
size = RoundUpTo(size, low_level_alloc_min_alignment);
if (allocated_end_ - allocated_current_ < (sptr)size) {
- uptr size_to_allocate = Max(size, GetPageSizeCached());
+ uptr size_to_allocate = RoundUpTo(size, GetPageSizeCached());
allocated_current_ =
(char*)MmapOrDie(size_to_allocate, __func__);
allocated_end_ = allocated_current_ + size_to_allocate;
diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_primary64.h b/libsanitizer/sanitizer_common/sanitizer_allocator_primary64.h
index 90603280e7c..1d9a29c70f3 100644
--- a/libsanitizer/sanitizer_common/sanitizer_allocator_primary64.h
+++ b/libsanitizer/sanitizer_common/sanitizer_allocator_primary64.h
@@ -72,11 +72,15 @@ class SizeClassAllocator64 {
void Init(s32 release_to_os_interval_ms) {
uptr TotalSpaceSize = kSpaceSize + AdditionalSize();
if (kUsingConstantSpaceBeg) {
+ CHECK(IsAligned(kSpaceBeg, SizeClassMap::kMaxSize));
CHECK_EQ(kSpaceBeg, address_range.Init(TotalSpaceSize,
PrimaryAllocatorName, kSpaceBeg));
} else {
- NonConstSpaceBeg = address_range.Init(TotalSpaceSize,
- PrimaryAllocatorName);
+ // Combined allocator expects that an 2^N allocation is always aligned to
+ // 2^N. For this to work, the start of the space needs to be aligned as
+ // high as the largest size class (which also needs to be a power of 2).
+ NonConstSpaceBeg = address_range.InitAligned(
+ TotalSpaceSize, SizeClassMap::kMaxSize, PrimaryAllocatorName);
CHECK_NE(NonConstSpaceBeg, ~(uptr)0);
}
SetReleaseToOSIntervalMs(release_to_os_interval_ms);
@@ -220,7 +224,7 @@ class SizeClassAllocator64 {
// Test-only.
void TestOnlyUnmap() {
- UnmapWithCallbackOrDie(SpaceBeg(), kSpaceSize + AdditionalSize());
+ UnmapWithCallbackOrDie((uptr)address_range.base(), address_range.size());
}
static void FillMemoryProfile(uptr start, uptr rss, bool file, uptr *stats,
diff --git a/libsanitizer/sanitizer_common/sanitizer_common.cpp b/libsanitizer/sanitizer_common/sanitizer_common.cpp
index f5f9f49d8cf..87efda5bd37 100644
--- a/libsanitizer/sanitizer_common/sanitizer_common.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_common.cpp
@@ -274,6 +274,7 @@ uptr ReadBinaryNameCached(/*out*/char *buf, uptr buf_len) {
return name_len;
}
+#if !SANITIZER_GO
void PrintCmdline() {
char **argv = GetArgv();
if (!argv) return;
@@ -282,6 +283,7 @@ void PrintCmdline() {
Printf("%s ", argv[i]);
Printf("\n\n");
}
+#endif
// Malloc hooks.
static const int kMaxMallocFreeHooks = 5;
diff --git a/libsanitizer/sanitizer_common/sanitizer_common.h b/libsanitizer/sanitizer_common/sanitizer_common.h
index 87b8f02b5b7..ac16e0e47ef 100644
--- a/libsanitizer/sanitizer_common/sanitizer_common.h
+++ b/libsanitizer/sanitizer_common/sanitizer_common.h
@@ -143,6 +143,7 @@ void RunFreeHooks(const void *ptr);
class ReservedAddressRange {
public:
uptr Init(uptr size, const char *name = nullptr, uptr fixed_addr = 0);
+ uptr InitAligned(uptr size, uptr align, const char *name = nullptr);
uptr Map(uptr fixed_addr, uptr size, const char *name = nullptr);
uptr MapOrDie(uptr fixed_addr, uptr size, const char *name = nullptr);
void Unmap(uptr addr, uptr size);
@@ -552,7 +553,7 @@ bool operator!=(const InternalMmapVectorNoCtor<T> &lhs,
template<typename T>
class InternalMmapVector : public InternalMmapVectorNoCtor<T> {
public:
- InternalMmapVector() { InternalMmapVectorNoCtor<T>::Initialize(1); }
+ InternalMmapVector() { InternalMmapVectorNoCtor<T>::Initialize(0); }
explicit InternalMmapVector(uptr cnt) {
InternalMmapVectorNoCtor<T>::Initialize(cnt);
this->resize(cnt);
@@ -855,7 +856,7 @@ INLINE uptr GetPthreadDestructorIterations() {
#endif
}
-void *internal_start_thread(void(*func)(void*), void *arg);
+void *internal_start_thread(void *(*func)(void*), void *arg);
void internal_join_thread(void *th);
void MaybeStartBackgroudThread();
diff --git a/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc b/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc
index 50e3558b52e..57f8b2d2944 100644
--- a/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc
+++ b/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc
@@ -79,13 +79,15 @@
#define devname __devname50
#define fgetpos __fgetpos50
#define fsetpos __fsetpos50
+#define fstatvfs __fstatvfs90
+#define fstatvfs1 __fstatvfs190
#define fts_children __fts_children60
#define fts_close __fts_close60
#define fts_open __fts_open60
#define fts_read __fts_read60
#define fts_set __fts_set60
#define getitimer __getitimer50
-#define getmntinfo __getmntinfo13
+#define getmntinfo __getmntinfo90
#define getpwent __getpwent50
#define getpwnam __getpwnam50
#define getpwnam_r __getpwnam_r50
@@ -95,6 +97,7 @@
#define getutxent __getutxent50
#define getutxid __getutxid50
#define getutxline __getutxline50
+#define getvfsstat __getvfsstat90
#define pututxline __pututxline50
#define glob __glob30
#define gmtime __gmtime50
@@ -110,12 +113,15 @@
#define setitimer __setitimer50
#define setlocale __setlocale50
#define shmctl __shmctl50
+#define sigaltstack __sigaltstack14
#define sigemptyset __sigemptyset14
#define sigfillset __sigfillset14
#define sigpending __sigpending14
#define sigprocmask __sigprocmask14
#define sigtimedwait __sigtimedwait50
#define stat __stat50
+#define statvfs __statvfs90
+#define statvfs1 __statvfs190
#define time __time50
#define times __times13
#define unvis __unvis50
@@ -128,11 +134,7 @@ extern const short *_tolower_tab_;
// Platform-specific options.
#if SANITIZER_MAC
-namespace __sanitizer {
-bool PlatformHasDifferentMemcpyAndMemmove();
-}
-#define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE \
- (__sanitizer::PlatformHasDifferentMemcpyAndMemmove())
+#define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE false
#elif SANITIZER_WINDOWS64
#define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE false
#else
@@ -4177,11 +4179,27 @@ INTERCEPTOR(int, pthread_mutex_unlock, void *m) {
#if SANITIZER_INTERCEPT___PTHREAD_MUTEX
INTERCEPTOR(int, __pthread_mutex_lock, void *m) {
- return WRAP(pthread_mutex_lock)(m);
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, __pthread_mutex_lock, m);
+ COMMON_INTERCEPTOR_MUTEX_PRE_LOCK(ctx, 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_POST_LOCK(ctx, m);
+ if (res == errno_EINVAL)
+ COMMON_INTERCEPTOR_MUTEX_INVALID(ctx, m);
+ return res;
}
INTERCEPTOR(int, __pthread_mutex_unlock, void *m) {
- return WRAP(pthread_mutex_unlock)(m);
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, __pthread_mutex_unlock, m);
+ COMMON_INTERCEPTOR_MUTEX_UNLOCK(ctx, m);
+ int res = REAL(__pthread_mutex_unlock)(m);
+ if (res == errno_EINVAL)
+ COMMON_INTERCEPTOR_MUTEX_INVALID(ctx, m);
+ return res;
}
#define INIT___PTHREAD_MUTEX_LOCK \
@@ -6411,12 +6429,11 @@ INTERCEPTOR(SSIZE_T, recvfrom, int fd, void *buf, SIZE_T len, int flags,
if (srcaddr) srcaddr_sz = *addrlen;
(void)srcaddr_sz; // prevent "set but not used" warning
SSIZE_T res = REAL(recvfrom)(fd, buf, len, flags, srcaddr, addrlen);
- if (res > 0) {
+ if (res > 0)
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, Min((SIZE_T)res, len));
- if (srcaddr)
- COMMON_INTERCEPTOR_INITIALIZE_RANGE(srcaddr,
- Min((SIZE_T)*addrlen, srcaddr_sz));
- }
+ if (res >= 0 && srcaddr)
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(srcaddr,
+ Min((SIZE_T)*addrlen, srcaddr_sz));
return res;
}
#define INIT_RECV_RECVFROM \
@@ -9623,6 +9640,148 @@ INTERCEPTOR(int, getentropy, void *buf, SIZE_T buflen) {
#define INIT_GETENTROPY
#endif
+#if SANITIZER_INTERCEPT_QSORT
+// Glibc qsort uses a temporary buffer allocated either on stack or on heap.
+// Poisoned memory from there may get copied into the comparator arguments,
+// where it needs to be dealt with. But even that is not enough - the results of
+// the sort may be copied into the input/output array based on the results of
+// the comparator calls, but directly from the temp memory, bypassing the
+// unpoisoning done in wrapped_qsort_compar. We deal with this by, again,
+// unpoisoning the entire array after the sort is done.
+//
+// We can not check that the entire array is initialized at the beginning. IMHO,
+// it's fine for parts of the sorted objects to contain uninitialized memory,
+// ex. as padding in structs.
+typedef int (*qsort_compar_f)(const void *, const void *);
+static THREADLOCAL qsort_compar_f qsort_compar;
+static THREADLOCAL SIZE_T qsort_size;
+int wrapped_qsort_compar(const void *a, const void *b) {
+ COMMON_INTERCEPTOR_UNPOISON_PARAM(2);
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(a, qsort_size);
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(b, qsort_size);
+ return qsort_compar(a, b);
+}
+
+INTERCEPTOR(void, qsort, void *base, SIZE_T nmemb, SIZE_T size,
+ qsort_compar_f compar) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, qsort, base, nmemb, size, compar);
+ // Run the comparator over all array elements to detect any memory issues.
+ if (nmemb > 1) {
+ for (SIZE_T i = 0; i < nmemb - 1; ++i) {
+ void *p = (void *)((char *)base + i * size);
+ void *q = (void *)((char *)base + (i + 1) * size);
+ COMMON_INTERCEPTOR_UNPOISON_PARAM(2);
+ compar(p, q);
+ }
+ }
+ qsort_compar_f old_compar = qsort_compar;
+ qsort_compar = compar;
+ SIZE_T old_size = qsort_size;
+ qsort_size = size;
+ REAL(qsort)(base, nmemb, size, wrapped_qsort_compar);
+ qsort_compar = old_compar;
+ qsort_size = old_size;
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, base, nmemb * size);
+}
+#define INIT_QSORT COMMON_INTERCEPT_FUNCTION(qsort)
+#else
+#define INIT_QSORT
+#endif
+
+#if SANITIZER_INTERCEPT_QSORT_R
+typedef int (*qsort_r_compar_f)(const void *, const void *, void *);
+static THREADLOCAL qsort_r_compar_f qsort_r_compar;
+static THREADLOCAL SIZE_T qsort_r_size;
+int wrapped_qsort_r_compar(const void *a, const void *b, void *arg) {
+ COMMON_INTERCEPTOR_UNPOISON_PARAM(3);
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(a, qsort_r_size);
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(b, qsort_r_size);
+ return qsort_r_compar(a, b, arg);
+}
+
+INTERCEPTOR(void, qsort_r, void *base, SIZE_T nmemb, SIZE_T size,
+ qsort_r_compar_f compar, void *arg) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, qsort_r, base, nmemb, size, compar, arg);
+ // Run the comparator over all array elements to detect any memory issues.
+ if (nmemb > 1) {
+ for (SIZE_T i = 0; i < nmemb - 1; ++i) {
+ void *p = (void *)((char *)base + i * size);
+ void *q = (void *)((char *)base + (i + 1) * size);
+ COMMON_INTERCEPTOR_UNPOISON_PARAM(3);
+ compar(p, q, arg);
+ }
+ }
+ qsort_r_compar_f old_compar = qsort_r_compar;
+ qsort_r_compar = compar;
+ SIZE_T old_size = qsort_r_size;
+ qsort_r_size = size;
+ REAL(qsort_r)(base, nmemb, size, wrapped_qsort_r_compar, arg);
+ qsort_r_compar = old_compar;
+ qsort_r_size = old_size;
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, base, nmemb * size);
+}
+#define INIT_QSORT_R COMMON_INTERCEPT_FUNCTION(qsort_r)
+#else
+#define INIT_QSORT_R
+#endif
+
+#if SANITIZER_INTERCEPT_SIGALTSTACK
+INTERCEPTOR(int, sigaltstack, void *ss, void *oss) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, sigaltstack, ss, oss);
+ int r = REAL(sigaltstack)(ss, oss);
+ if (r == 0 && oss != nullptr) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oss, struct_stack_t_sz);
+ }
+ return r;
+}
+#define INIT_SIGALTSTACK COMMON_INTERCEPT_FUNCTION(sigaltstack)
+#else
+#define INIT_SIGALTSTACK
+#endif
+
+#if SANITIZER_INTERCEPT_UNAME
+INTERCEPTOR(int, uname, struct utsname *utsname) {
+#if SANITIZER_LINUX
+ if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED)
+ return internal_uname(utsname);
+#endif
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, uname, utsname);
+ int res = REAL(uname)(utsname);
+ if (!res)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, utsname,
+ __sanitizer::struct_utsname_sz);
+ return res;
+}
+#define INIT_UNAME COMMON_INTERCEPT_FUNCTION(uname)
+#else
+#define INIT_UNAME
+#endif
+
+#if SANITIZER_INTERCEPT___XUNAME
+// FreeBSD's <sys/utsname.h> define uname() as
+// static __inline int uname(struct utsname *name) {
+// return __xuname(SYS_NMLN, (void*)name);
+// }
+INTERCEPTOR(int, __xuname, int size, void *utsname) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, __xuname, size, utsname);
+ int res = REAL(__xuname)(size, utsname);
+ if (!res)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, utsname,
+ __sanitizer::struct_utsname_sz);
+ return res;
+}
+#define INIT___XUNAME COMMON_INTERCEPT_FUNCTION(__xuname)
+#else
+#define INIT___XUNAME
+#endif
+
+#include "sanitizer_common_interceptors_netbsd_compat.inc"
+
static void InitializeCommonInterceptors() {
#if SI_POSIX
static u64 metadata_mem[sizeof(MetadataHashMap) / sizeof(u64) + 1];
@@ -9924,6 +10083,11 @@ static void InitializeCommonInterceptors() {
INIT_CRYPT;
INIT_CRYPT_R;
INIT_GETENTROPY;
+ INIT_QSORT;
+ INIT_QSORT_R;
+ INIT_SIGALTSTACK;
+ INIT_UNAME;
+ INIT___XUNAME;
INIT___PRINTF_CHK;
}
diff --git a/libsanitizer/sanitizer_common/sanitizer_common_interceptors_netbsd_compat.inc b/libsanitizer/sanitizer_common/sanitizer_common_interceptors_netbsd_compat.inc
new file mode 100644
index 00000000000..6aa73ec8c6a
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_common_interceptors_netbsd_compat.inc
@@ -0,0 +1,128 @@
+//===-- sanitizer_common_interceptors_netbsd_compat.inc ---------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Common function interceptors for tools like AddressSanitizer,
+// ThreadSanitizer, MemorySanitizer, etc.
+//
+// Interceptors for NetBSD old function calls that have been versioned.
+//
+// NetBSD minimal version supported 9.0.
+// NetBSD current version supported 9.99.26.
+//
+//===----------------------------------------------------------------------===//
+
+#if SANITIZER_NETBSD
+
+// First undef all mangled symbols.
+// Next, define compat interceptors.
+// Finally, undef INIT_ and redefine it.
+// This allows to avoid preprocessor issues.
+
+#undef fstatvfs
+#undef fstatvfs1
+#undef getmntinfo
+#undef getvfsstat
+#undef statvfs
+#undef statvfs1
+
+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);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(statvfs)(path, buf);
+ if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs90_sz);
+ return res;
+}
+
+INTERCEPTOR(int, fstatvfs, int fd, void *buf) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, fstatvfs, fd, buf);
+ COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(fstatvfs)(fd, buf);
+ if (!res) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs90_sz);
+ if (fd >= 0)
+ COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
+ }
+ return res;
+}
+
+#undef INIT_STATVFS
+#define INIT_STATVFS \
+ COMMON_INTERCEPT_FUNCTION(statvfs); \
+ COMMON_INTERCEPT_FUNCTION(fstatvfs); \
+ COMMON_INTERCEPT_FUNCTION(__statvfs90); \
+ COMMON_INTERCEPT_FUNCTION(__fstatvfs90)
+
+INTERCEPTOR(int, __getmntinfo13, void **mntbufp, int flags) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, __getmntinfo13, mntbufp, flags);
+ int cnt = REAL(__getmntinfo13)(mntbufp, flags);
+ if (cnt > 0 && mntbufp) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mntbufp, sizeof(void *));
+ if (*mntbufp)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *mntbufp, cnt * struct_statvfs90_sz);
+ }
+ return cnt;
+}
+
+#undef INIT_GETMNTINFO
+#define INIT_GETMNTINFO \
+ COMMON_INTERCEPT_FUNCTION(__getmntinfo13); \
+ COMMON_INTERCEPT_FUNCTION(__getmntinfo90)
+
+INTERCEPTOR(int, getvfsstat, void *buf, SIZE_T bufsize, int flags) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getvfsstat, buf, bufsize, flags);
+ int ret = REAL(getvfsstat)(buf, bufsize, flags);
+ if (buf && ret > 0)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, ret * struct_statvfs90_sz);
+ return ret;
+}
+
+#undef INIT_GETVFSSTAT
+#define INIT_GETVFSSTAT \
+ COMMON_INTERCEPT_FUNCTION(getvfsstat); \
+ COMMON_INTERCEPT_FUNCTION(__getvfsstat90)
+
+INTERCEPTOR(int, statvfs1, const char *path, void *buf, int flags) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, statvfs1, path, buf, flags);
+ if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
+ int res = REAL(statvfs1)(path, buf, flags);
+ if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs90_sz);
+ return res;
+}
+
+INTERCEPTOR(int, fstatvfs1, int fd, void *buf, int flags) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, fstatvfs1, fd, buf, flags);
+ COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
+ int res = REAL(fstatvfs1)(fd, buf, flags);
+ if (!res) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs90_sz);
+ if (fd >= 0)
+ COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
+ }
+ return res;
+}
+
+#undef INIT_STATVFS1
+#define INIT_STATVFS1 \
+ COMMON_INTERCEPT_FUNCTION(statvfs1); \
+ COMMON_INTERCEPT_FUNCTION(fstatvfs1); \
+ COMMON_INTERCEPT_FUNCTION(__statvfs190); \
+ COMMON_INTERCEPT_FUNCTION(__fstatvfs190)
+
+#endif
diff --git a/libsanitizer/sanitizer_common/sanitizer_common_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_common_libcdep.cpp
index 27d6a177760..0c918ebb4a9 100644
--- a/libsanitizer/sanitizer_common/sanitizer_common_libcdep.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_common_libcdep.cpp
@@ -30,7 +30,7 @@ SANITIZER_WEAK_ATTRIBUTE StackDepotStats *StackDepotGetStats() {
return nullptr;
}
-void BackgroundThread(void *arg) {
+void *BackgroundThread(void *arg) {
const uptr hard_rss_limit_mb = common_flags()->hard_rss_limit_mb;
const uptr soft_rss_limit_mb = common_flags()->soft_rss_limit_mb;
const bool heap_profile = common_flags()->heap_profile;
@@ -129,6 +129,16 @@ void SetSandboxingCallback(void (*f)()) {
sandboxing_callback = f;
}
+uptr ReservedAddressRange::InitAligned(uptr size, uptr align,
+ const char *name) {
+ CHECK(IsPowerOfTwo(align));
+ if (align <= GetPageSizeCached())
+ return Init(size, name);
+ uptr start = Init(size + align, name);
+ start += align - (start & (align - 1));
+ return start;
+}
+
} // namespace __sanitizer
SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_sandbox_on_notify,
diff --git a/libsanitizer/sanitizer_common/sanitizer_common_syscalls.inc b/libsanitizer/sanitizer_common/sanitizer_common_syscalls.inc
index 31ff48cfd2c..532ac9ead34 100644
--- a/libsanitizer/sanitizer_common/sanitizer_common_syscalls.inc
+++ b/libsanitizer/sanitizer_common/sanitizer_common_syscalls.inc
@@ -2885,6 +2885,23 @@ POST_SYSCALL(getrandom)(long res, void *buf, uptr count, long flags) {
POST_WRITE(buf, res);
}
}
+
+PRE_SYSCALL(sigaltstack)(const void *ss, void *oss) {
+ if (ss != nullptr) {
+ PRE_READ(ss, struct_stack_t_sz);
+ }
+ if (oss != nullptr) {
+ PRE_WRITE(oss, struct_stack_t_sz);
+ }
+}
+
+POST_SYSCALL(sigaltstack)(long res, void *ss, void *oss) {
+ if (res == 0) {
+ if (oss != nullptr) {
+ POST_WRITE(oss, struct_stack_t_sz);
+ }
+ }
+}
} // extern "C"
#undef PRE_SYSCALL
diff --git a/libsanitizer/sanitizer_common/sanitizer_coverage_fuchsia.cpp b/libsanitizer/sanitizer_common/sanitizer_coverage_fuchsia.cpp
index f18cee66b84..a52db08433e 100644
--- a/libsanitizer/sanitizer_common/sanitizer_coverage_fuchsia.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_coverage_fuchsia.cpp
@@ -27,15 +27,15 @@
#include "sanitizer_platform.h"
#if SANITIZER_FUCHSIA
+#include <zircon/process.h>
+#include <zircon/sanitizer.h>
+#include <zircon/syscalls.h>
+
#include "sanitizer_atomic.h"
#include "sanitizer_common.h"
#include "sanitizer_internal_defs.h"
#include "sanitizer_symbolizer_fuchsia.h"
-#include <zircon/process.h>
-#include <zircon/sanitizer.h>
-#include <zircon/syscalls.h>
-
using namespace __sanitizer;
namespace __sancov {
@@ -82,7 +82,8 @@ class TracePcGuardController final {
void TracePcGuard(u32 *guard, uptr pc) {
atomic_uint32_t *guard_ptr = reinterpret_cast<atomic_uint32_t *>(guard);
u32 idx = atomic_exchange(guard_ptr, 0, memory_order_relaxed);
- if (idx > 0) array_[idx] = pc;
+ if (idx > 0)
+ array_[idx] = pc;
}
void Dump() {
@@ -140,6 +141,10 @@ class TracePcGuardController final {
internal_getpid());
_zx_object_set_property(vmo_, ZX_PROP_NAME, vmo_name_,
internal_strlen(vmo_name_));
+ uint64_t size = DataSize();
+ status = _zx_object_set_property(vmo_, ZX_PROP_VMO_CONTENT_SIZE, &size,
+ sizeof(size));
+ CHECK_EQ(status, ZX_OK);
// Map the largest possible view we might need into the VMO. Later
// we might need to increase the VMO's size before we can use larger
@@ -172,6 +177,10 @@ class TracePcGuardController final {
zx_status_t status = _zx_vmo_set_size(vmo_, DataSize());
CHECK_EQ(status, ZX_OK);
+ uint64_t size = DataSize();
+ status = _zx_object_set_property(vmo_, ZX_PROP_VMO_CONTENT_SIZE, &size,
+ sizeof(size));
+ CHECK_EQ(status, ZX_OK);
return first_index;
}
@@ -204,13 +213,15 @@ SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_dump_coverage(const uptr *pcs,
}
SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard, u32 *guard) {
- if (!*guard) return;
+ if (!*guard)
+ return;
__sancov::pc_guard_controller.TracePcGuard(guard, GET_CALLER_PC() - 1);
}
SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard_init,
u32 *start, u32 *end) {
- if (start == end || *start) return;
+ if (start == end || *start)
+ return;
__sancov::pc_guard_controller.InitTracePcGuard(start, end);
}
diff --git a/libsanitizer/sanitizer_common/sanitizer_coverage_interface.inc b/libsanitizer/sanitizer_common/sanitizer_coverage_interface.inc
index 7beeff7e8af..d7ab0c3d98c 100644
--- a/libsanitizer/sanitizer_common/sanitizer_coverage_interface.inc
+++ b/libsanitizer/sanitizer_common/sanitizer_coverage_interface.inc
@@ -29,4 +29,5 @@ INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_pc_guard_init)
INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_pc_indir)
INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_switch)
INTERFACE_WEAK_FUNCTION(__sanitizer_cov_8bit_counters_init)
+INTERFACE_WEAK_FUNCTION(__sanitizer_cov_bool_flag_init)
INTERFACE_WEAK_FUNCTION(__sanitizer_cov_pcs_init)
diff --git a/libsanitizer/sanitizer_common/sanitizer_coverage_libcdep_new.cpp b/libsanitizer/sanitizer_common/sanitizer_coverage_libcdep_new.cpp
index 6a75792f926..73ebeb5fa14 100644
--- a/libsanitizer/sanitizer_common/sanitizer_coverage_libcdep_new.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_coverage_libcdep_new.cpp
@@ -207,6 +207,7 @@ SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_div8, void) {}
SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_gep, void) {}
SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_indir, void) {}
SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_8bit_counters_init, void) {}
+SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_bool_flag_init, void) {}
SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_pcs_init, void) {}
} // extern "C"
// Weak definition for code instrumented with -fsanitize-coverage=stack-depth
diff --git a/libsanitizer/sanitizer_common/sanitizer_file.h b/libsanitizer/sanitizer_common/sanitizer_file.h
index 4a78a0e0ac8..26681f0493d 100644
--- a/libsanitizer/sanitizer_common/sanitizer_file.h
+++ b/libsanitizer/sanitizer_common/sanitizer_file.h
@@ -87,8 +87,8 @@ bool IsAbsolutePath(const char *path);
// The child process will close all fds after STDERR_FILENO
// before passing control to a program.
pid_t StartSubprocess(const char *filename, const char *const argv[],
- fd_t stdin_fd = kInvalidFd, fd_t stdout_fd = kInvalidFd,
- fd_t stderr_fd = kInvalidFd);
+ const char *const envp[], fd_t stdin_fd = kInvalidFd,
+ fd_t stdout_fd = kInvalidFd, fd_t stderr_fd = kInvalidFd);
// Checks if specified process is still running
bool IsProcessRunning(pid_t pid);
// Waits for the process to finish and returns its exit code.
diff --git a/libsanitizer/sanitizer_common/sanitizer_flag_parser.cpp b/libsanitizer/sanitizer_common/sanitizer_flag_parser.cpp
index 1e2bc665261..9e274268bf2 100644
--- a/libsanitizer/sanitizer_common/sanitizer_flag_parser.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_flag_parser.cpp
@@ -56,9 +56,16 @@ char *FlagParser::ll_strndup(const char *s, uptr n) {
}
void FlagParser::PrintFlagDescriptions() {
+ char buffer[128];
+ buffer[sizeof(buffer) - 1] = '\0';
Printf("Available flags for %s:\n", SanitizerToolName);
- for (int i = 0; i < n_flags_; ++i)
- Printf("\t%s\n\t\t- %s\n", flags_[i].name, flags_[i].desc);
+ for (int i = 0; i < n_flags_; ++i) {
+ bool truncated = !(flags_[i].handler->Format(buffer, sizeof(buffer)));
+ CHECK_EQ(buffer[sizeof(buffer) - 1], '\0');
+ const char *truncation_str = truncated ? " Truncated" : "";
+ Printf("\t%s\n\t\t- %s (Current Value%s: %s)\n", flags_[i].name,
+ flags_[i].desc, truncation_str, buffer);
+ }
}
void FlagParser::fatal_error(const char *err) {
diff --git a/libsanitizer/sanitizer_common/sanitizer_flag_parser.h b/libsanitizer/sanitizer_common/sanitizer_flag_parser.h
index c24ad25626b..fac5dff3463 100644
--- a/libsanitizer/sanitizer_common/sanitizer_flag_parser.h
+++ b/libsanitizer/sanitizer_common/sanitizer_flag_parser.h
@@ -22,9 +22,23 @@ namespace __sanitizer {
class FlagHandlerBase {
public:
virtual bool Parse(const char *value) { return false; }
+ // Write the C string representation of the current value (truncated to fit)
+ // into the buffer of size `size`. Returns false if truncation occurred and
+ // returns true otherwise.
+ virtual bool Format(char *buffer, uptr size) {
+ if (size > 0)
+ buffer[0] = '\0';
+ return false;
+ }
protected:
~FlagHandlerBase() {}
+
+ inline bool FormatString(char *buffer, uptr size, const char *str_to_use) {
+ uptr num_symbols_should_write =
+ internal_snprintf(buffer, size, "%s", str_to_use);
+ return num_symbols_should_write < size;
+ }
};
template <typename T>
@@ -34,6 +48,7 @@ class FlagHandler : public FlagHandlerBase {
public:
explicit FlagHandler(T *t) : t_(t) {}
bool Parse(const char *value) final;
+ bool Format(char *buffer, uptr size) final;
};
inline bool ParseBool(const char *value, bool *b) {
@@ -59,6 +74,11 @@ inline bool FlagHandler<bool>::Parse(const char *value) {
return false;
}
+template <>
+inline bool FlagHandler<bool>::Format(char *buffer, uptr size) {
+ return FormatString(buffer, size, *t_ ? "true" : "false");
+}
+
template <>
inline bool FlagHandler<HandleSignalMode>::Parse(const char *value) {
bool b;
@@ -75,12 +95,23 @@ inline bool FlagHandler<HandleSignalMode>::Parse(const char *value) {
return false;
}
+template <>
+inline bool FlagHandler<HandleSignalMode>::Format(char *buffer, uptr size) {
+ uptr num_symbols_should_write = internal_snprintf(buffer, size, "%d", *t_);
+ return num_symbols_should_write < size;
+}
+
template <>
inline bool FlagHandler<const char *>::Parse(const char *value) {
*t_ = value;
return true;
}
+template <>
+inline bool FlagHandler<const char *>::Format(char *buffer, uptr size) {
+ return FormatString(buffer, size, *t_);
+}
+
template <>
inline bool FlagHandler<int>::Parse(const char *value) {
const char *value_end;
@@ -90,6 +121,12 @@ inline bool FlagHandler<int>::Parse(const char *value) {
return ok;
}
+template <>
+inline bool FlagHandler<int>::Format(char *buffer, uptr size) {
+ uptr num_symbols_should_write = internal_snprintf(buffer, size, "%d", *t_);
+ return num_symbols_should_write < size;
+}
+
template <>
inline bool FlagHandler<uptr>::Parse(const char *value) {
const char *value_end;
@@ -99,6 +136,12 @@ inline bool FlagHandler<uptr>::Parse(const char *value) {
return ok;
}
+template <>
+inline bool FlagHandler<uptr>::Format(char *buffer, uptr size) {
+ uptr num_symbols_should_write = internal_snprintf(buffer, size, "%p", *t_);
+ return num_symbols_should_write < size;
+}
+
template <>
inline bool FlagHandler<s64>::Parse(const char *value) {
const char *value_end;
@@ -108,6 +151,12 @@ inline bool FlagHandler<s64>::Parse(const char *value) {
return ok;
}
+template <>
+inline bool FlagHandler<s64>::Format(char *buffer, uptr size) {
+ uptr num_symbols_should_write = internal_snprintf(buffer, size, "%lld", *t_);
+ return num_symbols_should_write < size;
+}
+
class FlagParser {
static const int kMaxFlags = 200;
struct Flag {
diff --git a/libsanitizer/sanitizer_common/sanitizer_flags.cpp b/libsanitizer/sanitizer_common/sanitizer_flags.cpp
index 66a0a5579ed..684ee1e0b99 100644
--- a/libsanitizer/sanitizer_common/sanitizer_flags.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_flags.cpp
@@ -75,11 +75,13 @@ void SubstituteForFlagValue(const char *s, char *out, uptr out_size) {
class FlagHandlerInclude : public FlagHandlerBase {
FlagParser *parser_;
bool ignore_missing_;
+ const char *original_path_;
public:
explicit FlagHandlerInclude(FlagParser *parser, bool ignore_missing)
- : parser_(parser), ignore_missing_(ignore_missing) {}
+ : parser_(parser), ignore_missing_(ignore_missing), original_path_("") {}
bool Parse(const char *value) final {
+ original_path_ = value;
if (internal_strchr(value, '%')) {
char *buf = (char *)MmapOrDie(kMaxPathLength, "FlagHandlerInclude");
SubstituteForFlagValue(value, buf, kMaxPathLength);
@@ -89,6 +91,12 @@ class FlagHandlerInclude : public FlagHandlerBase {
}
return parser_->ParseFile(value, ignore_missing_);
}
+ bool Format(char *buffer, uptr size) {
+ // Note `original_path_` isn't actually what's parsed due to `%`
+ // substitutions. Printing the substituted path would require holding onto
+ // mmap'ed memory.
+ return FormatString(buffer, size, original_path_);
+ }
};
void RegisterIncludeFlags(FlagParser *parser, CommonFlags *cf) {
diff --git a/libsanitizer/sanitizer_common/sanitizer_freebsd.h b/libsanitizer/sanitizer_common/sanitizer_freebsd.h
index 64cb21f1c3d..82b227eab6d 100644
--- a/libsanitizer/sanitizer_common/sanitizer_freebsd.h
+++ b/libsanitizer/sanitizer_common/sanitizer_freebsd.h
@@ -19,11 +19,11 @@
// x86-64 FreeBSD 9.2 and older define 'ucontext_t' incorrectly in
// 32-bit mode.
#if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32)
-# include <osreldate.h>
-# if __FreeBSD_version <= 902001 // v9.2
-# include <link.h>
-# include <sys/param.h>
-# include <ucontext.h>
+#include <osreldate.h>
+#if __FreeBSD_version <= 902001 // v9.2
+#include <link.h>
+#include <sys/param.h>
+#include <ucontext.h>
namespace __sanitizer {
@@ -68,8 +68,8 @@ typedef struct __xmcontext {
} xmcontext_t;
typedef struct __xucontext {
- sigset_t uc_sigmask;
- xmcontext_t uc_mcontext;
+ sigset_t uc_sigmask;
+ xmcontext_t uc_mcontext;
struct __ucontext *uc_link;
stack_t uc_stack;
@@ -122,15 +122,16 @@ struct xdl_phdr_info {
void *dlpi_tls_data;
};
-typedef int (*__xdl_iterate_hdr_callback)(struct xdl_phdr_info*, size_t, void*);
-typedef int xdl_iterate_phdr_t(__xdl_iterate_hdr_callback, void*);
+typedef int (*__xdl_iterate_hdr_callback)(struct xdl_phdr_info *, size_t,
+ void *);
+typedef int xdl_iterate_phdr_t(__xdl_iterate_hdr_callback, void *);
#define xdl_iterate_phdr(callback, param) \
- (((xdl_iterate_phdr_t*) dl_iterate_phdr)((callback), (param)))
+ (((xdl_iterate_phdr_t *)dl_iterate_phdr)((callback), (param)))
} // namespace __sanitizer
-# endif // __FreeBSD_version <= 902001
+#endif // __FreeBSD_version <= 902001
#endif // SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32)
#endif // SANITIZER_FREEBSD_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_fuchsia.cpp b/libsanitizer/sanitizer_common/sanitizer_fuchsia.cpp
index 6e2c6137f0c..6d1ad794677 100644
--- a/libsanitizer/sanitizer_common/sanitizer_fuchsia.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_fuchsia.cpp
@@ -66,6 +66,10 @@ uptr internal_getpid() {
return pid;
}
+int internal_dlinfo(void *handle, int request, void *p) {
+ UNIMPLEMENTED();
+}
+
uptr GetThreadSelf() { return reinterpret_cast<uptr>(thrd_current()); }
tid_t GetTid() { return GetThreadSelf(); }
diff --git a/libsanitizer/sanitizer_common/sanitizer_fuchsia.h b/libsanitizer/sanitizer_common/sanitizer_fuchsia.h
index 5a2ad32b411..96f9cde7ef1 100644
--- a/libsanitizer/sanitizer_common/sanitizer_fuchsia.h
+++ b/libsanitizer/sanitizer_common/sanitizer_fuchsia.h
@@ -18,12 +18,18 @@
#include "sanitizer_common.h"
#include <zircon/sanitizer.h>
+#include <zircon/syscalls/object.h>
namespace __sanitizer {
extern uptr MainThreadStackBase, MainThreadStackSize;
extern sanitizer_shadow_bounds_t ShadowBounds;
+struct MemoryMappingLayoutData {
+ InternalMmapVector<zx_info_maps_t> data;
+ size_t current; // Current index into the vector.
+};
+
} // namespace __sanitizer
#endif // SANITIZER_FUCHSIA
diff --git a/libsanitizer/sanitizer_common/sanitizer_interceptors_ioctl_netbsd.inc b/libsanitizer/sanitizer_common/sanitizer_interceptors_ioctl_netbsd.inc
index 03ef7c1788c..576807ea3a6 100644
--- a/libsanitizer/sanitizer_common/sanitizer_interceptors_ioctl_netbsd.inc
+++ b/libsanitizer/sanitizer_common/sanitizer_interceptors_ioctl_netbsd.inc
@@ -24,7 +24,7 @@ struct ioctl_desc {
const char *name;
};
-const unsigned ioctl_table_max = 1236;
+const unsigned ioctl_table_max = 1238;
static ioctl_desc ioctl_table[ioctl_table_max];
static unsigned ioctl_table_size = 0;
@@ -166,9 +166,6 @@ static void ioctl_table_fill() {
_(FE_ENABLE_HIGH_LNB_VOLTAGE, READ, sizeof(int));
_(FE_SET_FRONTEND_TUNE_MODE, READ, sizeof(unsigned int));
_(FE_DISHNETWORK_SEND_LEGACY_CMD, READ, sizeof(unsigned long));
- /* Entries from file: dev/filemon/filemon.h */
- _(FILEMON_SET_FD, READWRITE, sizeof(int));
- _(FILEMON_SET_PID, READWRITE, sizeof(int));
/* Entries from file: dev/hdaudio/hdaudioio.h */
_(HDAUDIO_FGRP_INFO, READWRITE, struct_plistref_sz);
_(HDAUDIO_FGRP_GETCONFIG, READWRITE, struct_plistref_sz);
@@ -449,9 +446,6 @@ static void ioctl_table_fill() {
_(STICIO_STOPQ, NONE, 0);
/* Entries from file: dev/usb/ukyopon.h */
_(UKYOPON_IDENTIFY, WRITE, struct_ukyopon_identify_sz);
- /* Entries from file: dev/usb/urio.h */
- _(URIO_SEND_COMMAND, READWRITE, struct_urio_command_sz);
- _(URIO_RECV_COMMAND, READWRITE, struct_urio_command_sz);
/* Entries from file: dev/usb/usb.h */
_(USB_REQUEST, READWRITE, struct_usb_ctl_request_sz);
_(USB_SETDEBUG, READ, sizeof(int));
@@ -653,6 +647,7 @@ static void ioctl_table_fill() {
_(NVMM_IOC_MACHINE_CONFIGURE, READ, struct_nvmm_ioc_machine_configure_sz);
_(NVMM_IOC_VCPU_CREATE, READ, struct_nvmm_ioc_vcpu_create_sz);
_(NVMM_IOC_VCPU_DESTROY, READ, struct_nvmm_ioc_vcpu_destroy_sz);
+ _(NVMM_IOC_VCPU_CONFIGURE, READ, struct_nvmm_ioc_vcpu_configure_sz);
_(NVMM_IOC_VCPU_SETSTATE, READ, struct_nvmm_ioc_vcpu_setstate_sz);
_(NVMM_IOC_VCPU_GETSTATE, READ, struct_nvmm_ioc_vcpu_getstate_sz);
_(NVMM_IOC_VCPU_INJECT, READ, struct_nvmm_ioc_vcpu_inject_sz);
@@ -735,6 +730,7 @@ static void ioctl_table_fill() {
_(IOC_NPF_SAVE, WRITE, struct_nvlist_ref_sz);
_(IOC_NPF_RULE, READWRITE, struct_nvlist_ref_sz);
_(IOC_NPF_CONN_LOOKUP, READWRITE, struct_nvlist_ref_sz);
+ _(IOC_NPF_TABLE_REPLACE, READWRITE, struct_nvlist_ref_sz);
/* Entries from file: net/if_pppoe.h */
_(PPPOESETPARMS, READ, struct_pppoediscparms_sz);
_(PPPOEGETPARMS, READWRITE, struct_pppoediscparms_sz);
@@ -1403,8 +1399,14 @@ static void ioctl_table_fill() {
_(SNDCTL_DSP_SETRECVOL, READ, sizeof(unsigned int));
_(SNDCTL_DSP_SKIP, NONE, 0);
_(SNDCTL_DSP_SILENCE, NONE, 0);
+ /* Entries from file: dev/filemon/filemon.h (compat <= 9.99.26) */
+ _(FILEMON_SET_FD, READWRITE, sizeof(int));
+ _(FILEMON_SET_PID, READWRITE, sizeof(int));
+ /* Entries from file: dev/usb/urio.h (compat <= 9.99.43) */
+ _(URIO_SEND_COMMAND, READWRITE, struct_urio_command_sz);
+ _(URIO_RECV_COMMAND, READWRITE, struct_urio_command_sz);
#undef _
-} // NOLINT
+} // NOLINT
static bool ioctl_initialized = false;
diff --git a/libsanitizer/sanitizer_common/sanitizer_interface_internal.h b/libsanitizer/sanitizer_common/sanitizer_interface_internal.h
index c110eff130f..be8023e9e16 100644
--- a/libsanitizer/sanitizer_common/sanitizer_interface_internal.h
+++ b/libsanitizer/sanitizer_common/sanitizer_interface_internal.h
@@ -109,8 +109,10 @@ extern "C" {
__sanitizer::u32*);
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
void __sanitizer_cov_8bit_counters_init();
- SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
- void __sanitizer_cov_pcs_init();
+ SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void
+ __sanitizer_cov_bool_flag_init();
+ SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void
+ __sanitizer_cov_pcs_init();
} // extern "C"
#endif // SANITIZER_INTERFACE_INTERNAL_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_internal_defs.h b/libsanitizer/sanitizer_common/sanitizer_internal_defs.h
index 00226305e07..d0ffc79b061 100644
--- a/libsanitizer/sanitizer_common/sanitizer_internal_defs.h
+++ b/libsanitizer/sanitizer_common/sanitizer_internal_defs.h
@@ -105,7 +105,7 @@
// FIXME: do we have anything like this on Mac?
#ifndef SANITIZER_CAN_USE_PREINIT_ARRAY
#if ((SANITIZER_LINUX && !SANITIZER_ANDROID) || SANITIZER_OPENBSD || \
- SANITIZER_FUCHSIA) && !defined(PIC)
+ SANITIZER_FUCHSIA || SANITIZER_NETBSD) && !defined(PIC)
#define SANITIZER_CAN_USE_PREINIT_ARRAY 1
// Before Solaris 11.4, .preinit_array is fully supported only with GNU ld.
// FIXME: Check for those conditions.
diff --git a/libsanitizer/sanitizer_common/sanitizer_libc.h b/libsanitizer/sanitizer_common/sanitizer_libc.h
index 3d5db35d68b..ec0a6ded009 100644
--- a/libsanitizer/sanitizer_common/sanitizer_libc.h
+++ b/libsanitizer/sanitizer_common/sanitizer_libc.h
@@ -72,6 +72,8 @@ unsigned int internal_sleep(unsigned int seconds);
uptr internal_getpid();
uptr internal_getppid();
+int internal_dlinfo(void *handle, int request, void *p);
+
// Threading
uptr internal_sched_yield();
diff --git a/libsanitizer/sanitizer_common/sanitizer_linux.cpp b/libsanitizer/sanitizer_common/sanitizer_linux.cpp
index 3807a79b1cd..2168301fd69 100644
--- a/libsanitizer/sanitizer_common/sanitizer_linux.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_linux.cpp
@@ -26,7 +26,7 @@
#include "sanitizer_placement_new.h"
#include "sanitizer_procmaps.h"
-#if SANITIZER_LINUX
+#if SANITIZER_LINUX && !SANITIZER_GO
#include <asm/param.h>
#endif
@@ -166,7 +166,7 @@ namespace __sanitizer {
#if !SANITIZER_SOLARIS && !SANITIZER_NETBSD
#if !SANITIZER_S390 && !SANITIZER_OPENBSD
uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd,
- OFF_T offset) {
+ u64 offset) {
#if SANITIZER_FREEBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS
return internal_syscall(SYSCALL(mmap), (uptr)addr, length, prot, flags, fd,
offset);
@@ -552,13 +552,14 @@ const char *GetEnv(const char *name) {
#endif
}
-#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD && !SANITIZER_OPENBSD
+#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD && !SANITIZER_OPENBSD && \
+ !SANITIZER_GO
extern "C" {
SANITIZER_WEAK_ATTRIBUTE extern void *__libc_stack_end;
}
#endif
-#if !SANITIZER_GO && !SANITIZER_FREEBSD && !SANITIZER_NETBSD && \
+#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD && \
!SANITIZER_OPENBSD
static void ReadNullSepFileToArray(const char *path, char ***arr,
int arr_size) {
@@ -604,16 +605,21 @@ static void GetArgsAndEnv(char ***argv, char ***envp) {
#else // SANITIZER_FREEBSD
#if !SANITIZER_GO
if (&__libc_stack_end) {
-#endif // !SANITIZER_GO
uptr* stack_end = (uptr*)__libc_stack_end;
- int argc = *stack_end;
+ // Normally argc can be obtained from *stack_end, however, on ARM glibc's
+ // _start clobbers it:
+ // https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/arm/start.S;hb=refs/heads/release/2.31/master#l75
+ // Do not special-case ARM and infer argc from argv everywhere.
+ int argc = 0;
+ while (stack_end[argc + 1]) argc++;
*argv = (char**)(stack_end + 1);
*envp = (char**)(stack_end + argc + 2);
-#if !SANITIZER_GO
} else {
+#endif // !SANITIZER_GO
static const int kMaxArgv = 2000, kMaxEnvp = 2000;
ReadNullSepFileToArray("/proc/self/cmdline", argv, kMaxArgv);
ReadNullSepFileToArray("/proc/self/environ", envp, kMaxEnvp);
+#if !SANITIZER_GO
}
#endif // !SANITIZER_GO
#endif // SANITIZER_FREEBSD
@@ -735,6 +741,14 @@ uptr internal_getppid() {
return internal_syscall(SYSCALL(getppid));
}
+int internal_dlinfo(void *handle, int request, void *p) {
+#if SANITIZER_FREEBSD
+ return dlinfo(handle, request, p);
+#else
+ UNIMPLEMENTED();
+#endif
+}
+
uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count) {
#if SANITIZER_FREEBSD
return internal_syscall(SYSCALL(getdirentries), fd, (uptr)dirp, count, NULL);
@@ -1006,9 +1020,8 @@ static uptr GetKernelAreaSize() {
// is modified (e.g. under schroot) so check this as well.
struct utsname uname_info;
int pers = personality(0xffffffffUL);
- if (!(pers & PER_MASK)
- && uname(&uname_info) == 0
- && internal_strstr(uname_info.machine, "64"))
+ if (!(pers & PER_MASK) && internal_uname(&uname_info) == 0 &&
+ internal_strstr(uname_info.machine, "64"))
return 0;
#endif // SANITIZER_ANDROID
@@ -1063,7 +1076,8 @@ uptr GetMaxUserVirtualAddress() {
#if !SANITIZER_ANDROID
uptr GetPageSize() {
-#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__i386__))
+#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__i386__)) && \
+ defined(EXEC_PAGESIZE)
return EXEC_PAGESIZE;
#elif SANITIZER_FREEBSD || SANITIZER_NETBSD
// Use sysctl as sysconf can trigger interceptors internally.
@@ -1619,6 +1633,12 @@ uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
}
#endif // defined(__x86_64__) && SANITIZER_LINUX
+#if SANITIZER_LINUX
+int internal_uname(struct utsname *buf) {
+ return internal_syscall(SYSCALL(uname), buf);
+}
+#endif
+
#if SANITIZER_ANDROID
#if __ANDROID_API__ < 21
extern "C" __attribute__((weak)) int dl_iterate_phdr(
@@ -1701,7 +1721,7 @@ HandleSignalMode GetHandleSignalMode(int signum) {
}
#if !SANITIZER_GO
-void *internal_start_thread(void(*func)(void *arg), void *arg) {
+void *internal_start_thread(void *(*func)(void *arg), void *arg) {
// Start the thread with signals blocked, otherwise it can steal user signals.
__sanitizer_sigset_t set, old;
internal_sigfillset(&set);
@@ -1712,7 +1732,7 @@ void *internal_start_thread(void(*func)(void *arg), void *arg) {
#endif
internal_sigprocmask(SIG_SETMASK, &set, &old);
void *th;
- real_pthread_create(&th, nullptr, (void*(*)(void *arg))func, arg);
+ real_pthread_create(&th, nullptr, func, arg);
internal_sigprocmask(SIG_SETMASK, &old, nullptr);
return th;
}
@@ -1721,7 +1741,7 @@ void internal_join_thread(void *th) {
real_pthread_join(th, nullptr);
}
#else
-void *internal_start_thread(void (*func)(void *), void *arg) { return 0; }
+void *internal_start_thread(void *(*func)(void *), void *arg) { return 0; }
void internal_join_thread(void *th) {}
#endif
@@ -1846,6 +1866,105 @@ SignalContext::WriteFlag SignalContext::GetWriteFlag() const {
#endif
u32 instr = *(u32 *)pc;
return (instr >> 21) & 1 ? WRITE: READ;
+#elif defined(__riscv)
+ unsigned long pc = ucontext->uc_mcontext.__gregs[REG_PC];
+ unsigned faulty_instruction = *(uint16_t *)pc;
+
+#if defined(__riscv_compressed)
+ if ((faulty_instruction & 0x3) != 0x3) { // it's a compressed instruction
+ // set op_bits to the instruction bits [1, 0, 15, 14, 13]
+ unsigned op_bits =
+ ((faulty_instruction & 0x3) << 3) | (faulty_instruction >> 13);
+ unsigned rd = faulty_instruction & 0xF80; // bits 7-11, inclusive
+ switch (op_bits) {
+ case 0b10'010: // c.lwsp (rd != x0)
+#if __riscv_xlen == 64
+ case 0b10'011: // c.ldsp (rd != x0)
+#endif
+ return rd ? SignalContext::READ : SignalContext::UNKNOWN;
+ case 0b00'010: // c.lw
+#if __riscv_flen >= 32 && __riscv_xlen == 32
+ case 0b10'011: // c.flwsp
+#endif
+#if __riscv_flen >= 32 || __riscv_xlen == 64
+ case 0b00'011: // c.flw / c.ld
+#endif
+#if __riscv_flen == 64
+ case 0b00'001: // c.fld
+ case 0b10'001: // c.fldsp
+#endif
+ return SignalContext::READ;
+ case 0b00'110: // c.sw
+ case 0b10'110: // c.swsp
+#if __riscv_flen >= 32 || __riscv_xlen == 64
+ case 0b00'111: // c.fsw / c.sd
+ case 0b10'111: // c.fswsp / c.sdsp
+#endif
+#if __riscv_flen == 64
+ case 0b00'101: // c.fsd
+ case 0b10'101: // c.fsdsp
+#endif
+ return SignalContext::WRITE;
+ default:
+ return SignalContext::UNKNOWN;
+ }
+ }
+#endif
+
+ unsigned opcode = faulty_instruction & 0x7f; // lower 7 bits
+ unsigned funct3 = (faulty_instruction >> 12) & 0x7; // bits 12-14, inclusive
+ switch (opcode) {
+ case 0b0000011: // loads
+ switch (funct3) {
+ case 0b000: // lb
+ case 0b001: // lh
+ case 0b010: // lw
+#if __riscv_xlen == 64
+ case 0b011: // ld
+#endif
+ case 0b100: // lbu
+ case 0b101: // lhu
+ return SignalContext::READ;
+ default:
+ return SignalContext::UNKNOWN;
+ }
+ case 0b0100011: // stores
+ switch (funct3) {
+ case 0b000: // sb
+ case 0b001: // sh
+ case 0b010: // sw
+#if __riscv_xlen == 64
+ case 0b011: // sd
+#endif
+ return SignalContext::WRITE;
+ default:
+ return SignalContext::UNKNOWN;
+ }
+#if __riscv_flen >= 32
+ case 0b0000111: // floating-point loads
+ switch (funct3) {
+ case 0b010: // flw
+#if __riscv_flen == 64
+ case 0b011: // fld
+#endif
+ return SignalContext::READ;
+ default:
+ return SignalContext::UNKNOWN;
+ }
+ case 0b0100111: // floating-point stores
+ switch (funct3) {
+ case 0b010: // fsw
+#if __riscv_flen == 64
+ case 0b011: // fsd
+#endif
+ return SignalContext::WRITE;
+ default:
+ return SignalContext::UNKNOWN;
+ }
+#endif
+ default:
+ return SignalContext::UNKNOWN;
+ }
#else
(void)ucontext;
return UNKNOWN; // FIXME: Implement.
@@ -2011,7 +2130,9 @@ void CheckASLR() {
}
if (UNLIKELY(paxflags & CTL_PROC_PAXFLAGS_ASLR)) {
- Printf("This sanitizer is not compatible with enabled ASLR\n");
+ Printf("This sanitizer is not compatible with enabled ASLR.\n"
+ "To disable ASLR, please run \"paxctl +a %s\" and try again.\n",
+ GetArgv()[0]);
Die();
}
#elif SANITIZER_PPC64V2
diff --git a/libsanitizer/sanitizer_common/sanitizer_linux.h b/libsanitizer/sanitizer_common/sanitizer_linux.h
index c28347ad963..c162d1ca5d2 100644
--- a/libsanitizer/sanitizer_common/sanitizer_linux.h
+++ b/libsanitizer/sanitizer_common/sanitizer_linux.h
@@ -25,6 +25,7 @@
#include "sanitizer_posix.h"
struct link_map; // Opaque type returned by dlopen().
+struct utsname;
namespace __sanitizer {
// Dirent structure for getdents(). Note that this structure is different from
@@ -65,6 +66,7 @@ void internal_sigdelset(__sanitizer_sigset_t *set, int signum);
uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
int *parent_tidptr, void *newtls, int *child_tidptr);
#endif
+int internal_uname(struct utsname *buf);
#elif SANITIZER_FREEBSD
void internal_sigdelset(__sanitizer_sigset_t *set, int signum);
#elif SANITIZER_NETBSD
diff --git a/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp
index e09d568d802..4d17c9686e4 100644
--- a/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp
@@ -35,6 +35,10 @@
#include <sys/resource.h>
#include <syslog.h>
+#if !defined(ElfW)
+#define ElfW(type) Elf_##type
+#endif
+
#if SANITIZER_FREEBSD
#include <pthread_np.h>
#include <osreldate.h>
@@ -50,6 +54,7 @@
#if SANITIZER_NETBSD
#include <sys/sysctl.h>
#include <sys/tls.h>
+#include <lwp.h>
#endif
#if SANITIZER_SOLARIS
@@ -399,13 +404,7 @@ uptr ThreadSelf() {
#if SANITIZER_NETBSD
static struct tls_tcb * ThreadSelfTlsTcb() {
- struct tls_tcb * tcb;
-# ifdef __HAVE___LWP_GETTCB_FAST
- tcb = (struct tls_tcb *)__lwp_gettcb_fast();
-# elif defined(__HAVE___LWP_GETPRIVATE_FAST)
- tcb = (struct tls_tcb *)__lwp_getprivate_fast();
-# endif
- return tcb;
+ return (struct tls_tcb *)_lwp_getprivate();
}
uptr ThreadSelf() {
@@ -698,13 +697,9 @@ u32 GetNumberOfCPUs() {
#elif SANITIZER_SOLARIS
return sysconf(_SC_NPROCESSORS_ONLN);
#else
-#if defined(CPU_COUNT)
cpu_set_t CPUs;
CHECK_EQ(sched_getaffinity(0, sizeof(cpu_set_t), &CPUs), 0);
return CPU_COUNT(&CPUs);
-#else
- return 1;
-#endif
#endif
}
diff --git a/libsanitizer/sanitizer_common/sanitizer_linux_s390.cpp b/libsanitizer/sanitizer_common/sanitizer_linux_s390.cpp
index 41e187eaf8d..bb2f5b5f9f7 100644
--- a/libsanitizer/sanitizer_common/sanitizer_linux_s390.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_linux_s390.cpp
@@ -15,19 +15,20 @@
#if SANITIZER_LINUX && SANITIZER_S390
-#include "sanitizer_libc.h"
-#include "sanitizer_linux.h"
-
+#include <dlfcn.h>
#include <errno.h>
#include <sys/syscall.h>
#include <sys/utsname.h>
#include <unistd.h>
+#include "sanitizer_libc.h"
+#include "sanitizer_linux.h"
+
namespace __sanitizer {
// --------------- sanitizer_libc.h
uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd,
- OFF_T offset) {
+ u64 offset) {
struct s390_mmap_params {
unsigned long addr;
unsigned long length;
@@ -123,7 +124,7 @@ static bool FixedCVE_2016_2143() {
struct utsname buf;
unsigned int major, minor, patch = 0;
// This should never fail, but just in case...
- if (uname(&buf))
+ if (internal_uname(&buf))
return false;
const char *ptr = buf.release;
major = internal_simple_strtoll(ptr, &ptr, 10);
diff --git a/libsanitizer/sanitizer_common/sanitizer_mac.cpp b/libsanitizer/sanitizer_common/sanitizer_mac.cpp
index b971ad058e9..7550545ea6f 100644
--- a/libsanitizer/sanitizer_common/sanitizer_mac.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_mac.cpp
@@ -30,6 +30,7 @@
#include "sanitizer_placement_new.h"
#include "sanitizer_platform_limits_posix.h"
#include "sanitizer_procmaps.h"
+#include "sanitizer_ptrauth.h"
#if !SANITIZER_IOS
#include <crt_externs.h> // for _NSGetEnviron
@@ -37,7 +38,7 @@
extern char **environ;
#endif
-#if defined(__has_include) && __has_include(<os/trace.h>) && defined(__BLOCKS__)
+#if defined(__has_include) && __has_include(<os/trace.h>)
#define SANITIZER_OS_TRACE 1
#include <os/trace.h>
#else
@@ -208,6 +209,10 @@ uptr internal_getpid() {
return getpid();
}
+int internal_dlinfo(void *handle, int request, void *p) {
+ UNIMPLEMENTED();
+}
+
int internal_sigaction(int signum, const void *act, void *oldact) {
return sigaction(signum,
(const struct sigaction *)act, (struct sigaction *)oldact);
@@ -242,7 +247,8 @@ int internal_sysctlbyname(const char *sname, void *oldp, uptr *oldlenp,
(size_t)newlen);
}
-static fd_t internal_spawn_impl(const char *argv[], pid_t *pid) {
+static fd_t internal_spawn_impl(const char *argv[], const char *envp[],
+ pid_t *pid) {
fd_t master_fd = kInvalidFd;
fd_t slave_fd = kInvalidFd;
@@ -298,8 +304,8 @@ static fd_t internal_spawn_impl(const char *argv[], pid_t *pid) {
// posix_spawn
char **argv_casted = const_cast<char **>(argv);
- char **env = GetEnviron();
- res = posix_spawn(pid, argv[0], &acts, &attrs, argv_casted, env);
+ char **envp_casted = const_cast<char **>(envp);
+ res = posix_spawn(pid, argv[0], &acts, &attrs, argv_casted, envp_casted);
if (res != 0) return kInvalidFd;
// Disable echo in the new terminal, disable CR.
@@ -316,7 +322,7 @@ static fd_t internal_spawn_impl(const char *argv[], pid_t *pid) {
return fd;
}
-fd_t internal_spawn(const char *argv[], pid_t *pid) {
+fd_t internal_spawn(const char *argv[], const char *envp[], pid_t *pid) {
// The client program may close its stdin and/or stdout and/or stderr thus
// allowing open/posix_openpt to reuse file descriptors 0, 1 or 2. In this
// case the communication is broken if either the parent or the child tries to
@@ -331,7 +337,7 @@ fd_t internal_spawn(const char *argv[], pid_t *pid) {
break;
}
- fd_t fd = internal_spawn_impl(argv, pid);
+ fd_t fd = internal_spawn_impl(argv, envp, pid);
for (; count > 0; count--) {
internal_close(low_fds[count]);
@@ -623,19 +629,13 @@ MacosVersion GetMacosVersionInternal() {
if (*p != '.') return MACOS_VERSION_UNKNOWN;
switch (major) {
- case 9: return MACOS_VERSION_LEOPARD;
- case 10: return MACOS_VERSION_SNOW_LEOPARD;
case 11: return MACOS_VERSION_LION;
case 12: return MACOS_VERSION_MOUNTAIN_LION;
case 13: return MACOS_VERSION_MAVERICKS;
case 14: return MACOS_VERSION_YOSEMITE;
case 15: return MACOS_VERSION_EL_CAPITAN;
case 16: return MACOS_VERSION_SIERRA;
- case 17:
- // Not a typo, 17.5 Darwin Kernel Version maps to High Sierra 10.13.4.
- if (minor >= 5)
- return MACOS_VERSION_HIGH_SIERRA_DOT_RELEASE_4;
- return MACOS_VERSION_HIGH_SIERRA;
+ case 17: return MACOS_VERSION_HIGH_SIERRA;
case 18: return MACOS_VERSION_MOJAVE;
case 19: return MACOS_VERSION_CATALINA;
default:
@@ -656,13 +656,21 @@ MacosVersion GetMacosVersion() {
return result;
}
-bool PlatformHasDifferentMemcpyAndMemmove() {
- // On OS X 10.7 memcpy() and memmove() are both resolved
- // into memmove$VARIANT$sse42.
- // See also https://github.com/google/sanitizers/issues/34.
- // TODO(glider): need to check dynamically that memcpy() and memmove() are
- // actually the same function.
- return GetMacosVersion() == MACOS_VERSION_SNOW_LEOPARD;
+DarwinKernelVersion GetDarwinKernelVersion() {
+ char buf[100];
+ size_t len = sizeof(buf);
+ int res = internal_sysctlbyname("kern.osrelease", buf, &len, nullptr, 0);
+ CHECK_EQ(res, 0);
+
+ // Format: <major>.<minor>.<patch>\0
+ CHECK_GE(len, 6);
+ const char *p = buf;
+ u16 major = internal_simple_strtoll(p, &p, /*base=*/10);
+ CHECK_EQ(*p, '.');
+ p += 1;
+ u16 minor = internal_simple_strtoll(p, &p, /*base=*/10);
+
+ return DarwinKernelVersion(major, minor);
}
uptr GetRSS() {
@@ -677,13 +685,13 @@ uptr GetRSS() {
return info.resident_size;
}
-void *internal_start_thread(void(*func)(void *arg), void *arg) {
+void *internal_start_thread(void *(*func)(void *arg), void *arg) {
// Start the thread with signals blocked, otherwise it can steal user signals.
__sanitizer_sigset_t set, old;
internal_sigfillset(&set);
internal_sigprocmask(SIG_SETMASK, &set, &old);
pthread_t th;
- pthread_create(&th, 0, (void*(*)(void *arg))func, arg);
+ pthread_create(&th, 0, func, arg);
internal_sigprocmask(SIG_SETMASK, &old, 0);
return th;
}
@@ -760,16 +768,24 @@ bool SignalContext::IsTrueFaultingAddress() const {
return si->si_signo == SIGSEGV && si->si_code != 0;
}
+#if defined(__aarch64__) && defined(arm_thread_state64_get_sp)
+ #define AARCH64_GET_REG(r) \
+ (uptr)ptrauth_strip( \
+ (void *)arm_thread_state64_get_##r(ucontext->uc_mcontext->__ss), 0)
+#else
+ #define AARCH64_GET_REG(r) ucontext->uc_mcontext->__ss.__##r
+#endif
+
static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
ucontext_t *ucontext = (ucontext_t*)context;
# if defined(__aarch64__)
- *pc = ucontext->uc_mcontext->__ss.__pc;
+ *pc = AARCH64_GET_REG(pc);
# if defined(__IPHONE_8_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_8_0
- *bp = ucontext->uc_mcontext->__ss.__fp;
+ *bp = AARCH64_GET_REG(fp);
# else
- *bp = ucontext->uc_mcontext->__ss.__lr;
+ *bp = AARCH64_GET_REG(lr);
# endif
- *sp = ucontext->uc_mcontext->__ss.__sp;
+ *sp = AARCH64_GET_REG(sp);
# elif defined(__x86_64__)
*pc = ucontext->uc_mcontext->__ss.__rip;
*bp = ucontext->uc_mcontext->__ss.__rbp;
@@ -787,13 +803,16 @@ static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
# endif
}
-void SignalContext::InitPcSpBp() { GetPcSpBp(context, &pc, &sp, &bp); }
+void SignalContext::InitPcSpBp() {
+ addr = (uptr)ptrauth_strip((void *)addr, 0);
+ GetPcSpBp(context, &pc, &sp, &bp);
+}
void InitializePlatformEarly() {
- // Only use xnu_fast_mmap when on x86_64 and the OS supports it.
+ // Only use xnu_fast_mmap when on x86_64 and the kernel supports it.
use_xnu_fast_mmap =
#if defined(__x86_64__)
- GetMacosVersion() >= MACOS_VERSION_HIGH_SIERRA_DOT_RELEASE_4;
+ GetDarwinKernelVersion() >= DarwinKernelVersion(17, 5);
#else
false;
#endif
@@ -1123,6 +1142,8 @@ void SignalContext::DumpAllRegisters(void *context) {
ucontext_t *ucontext = (ucontext_t*)context;
# define DUMPREG64(r) \
Printf("%s = 0x%016llx ", #r, ucontext->uc_mcontext->__ss.__ ## r);
+# define DUMPREGA64(r) \
+ Printf(" %s = 0x%016llx ", #r, AARCH64_GET_REG(r));
# define DUMPREG32(r) \
Printf("%s = 0x%08x ", #r, ucontext->uc_mcontext->__ss.__ ## r);
# define DUMPREG_(r) Printf(" "); DUMPREG(r);
@@ -1148,7 +1169,7 @@ void SignalContext::DumpAllRegisters(void *context) {
DUMPREG(x[16]); DUMPREG(x[17]); DUMPREG(x[18]); DUMPREG(x[19]); Printf("\n");
DUMPREG(x[20]); DUMPREG(x[21]); DUMPREG(x[22]); DUMPREG(x[23]); Printf("\n");
DUMPREG(x[24]); DUMPREG(x[25]); DUMPREG(x[26]); DUMPREG(x[27]); Printf("\n");
- DUMPREG(x[28]); DUMPREG___(fp); DUMPREG___(lr); DUMPREG___(sp); Printf("\n");
+ DUMPREG(x[28]); DUMPREGA64(fp); DUMPREGA64(lr); DUMPREGA64(sp); Printf("\n");
# elif defined(__arm__)
# define DUMPREG(r) DUMPREG32(r)
DUMPREG_(r[0]); DUMPREG_(r[1]); DUMPREG_(r[2]); DUMPREG_(r[3]); Printf("\n");
diff --git a/libsanitizer/sanitizer_common/sanitizer_mac.h b/libsanitizer/sanitizer_common/sanitizer_mac.h
index 2257883084e..34dc2c05dcf 100644
--- a/libsanitizer/sanitizer_common/sanitizer_mac.h
+++ b/libsanitizer/sanitizer_common/sanitizer_mac.h
@@ -33,22 +33,35 @@ struct MemoryMappingLayoutData {
enum MacosVersion {
MACOS_VERSION_UNINITIALIZED = 0,
MACOS_VERSION_UNKNOWN,
- MACOS_VERSION_LEOPARD,
- MACOS_VERSION_SNOW_LEOPARD,
- MACOS_VERSION_LION,
+ MACOS_VERSION_LION, // macOS 10.7; oldest currently supported
MACOS_VERSION_MOUNTAIN_LION,
MACOS_VERSION_MAVERICKS,
MACOS_VERSION_YOSEMITE,
MACOS_VERSION_EL_CAPITAN,
MACOS_VERSION_SIERRA,
MACOS_VERSION_HIGH_SIERRA,
- MACOS_VERSION_HIGH_SIERRA_DOT_RELEASE_4,
MACOS_VERSION_MOJAVE,
MACOS_VERSION_CATALINA,
MACOS_VERSION_UNKNOWN_NEWER
};
+struct DarwinKernelVersion {
+ u16 major;
+ u16 minor;
+
+ DarwinKernelVersion(u16 major, u16 minor) : major(major), minor(minor) {}
+
+ bool operator==(const DarwinKernelVersion &other) const {
+ return major == other.major && minor == other.minor;
+ }
+ bool operator>=(const DarwinKernelVersion &other) const {
+ return major >= other.major ||
+ (major == other.major && minor >= other.minor);
+ }
+};
+
MacosVersion GetMacosVersion();
+DarwinKernelVersion GetDarwinKernelVersion();
char **GetEnviron();
diff --git a/libsanitizer/sanitizer_common/sanitizer_malloc_mac.inc b/libsanitizer/sanitizer_common/sanitizer_malloc_mac.inc
index 11adbe5c25b..647bcdfe105 100644
--- a/libsanitizer/sanitizer_common/sanitizer_malloc_mac.inc
+++ b/libsanitizer/sanitizer_common/sanitizer_malloc_mac.inc
@@ -61,12 +61,10 @@ INTERCEPTOR(malloc_zone_t *, malloc_create_zone,
malloc_zone_t *new_zone = (malloc_zone_t *)p;
internal_memcpy(new_zone, &sanitizer_zone, sizeof(sanitizer_zone));
new_zone->zone_name = NULL; // The name will be changed anyway.
- if (GetMacosVersion() >= MACOS_VERSION_LION) {
- // Prevent the client app from overwriting the zone contents.
- // Library functions that need to modify the zone will set PROT_WRITE on it.
- // This matches the behavior of malloc_create_zone() on OSX 10.7 and higher.
- mprotect(new_zone, allocated_size, PROT_READ);
- }
+ // Prevent the client app from overwriting the zone contents.
+ // Library functions that need to modify the zone will set PROT_WRITE on it.
+ // This matches the behavior of malloc_create_zone() on OSX 10.7 and higher.
+ mprotect(new_zone, allocated_size, PROT_READ);
// We're explicitly *NOT* registering the zone.
return new_zone;
}
@@ -75,11 +73,9 @@ INTERCEPTOR(void, malloc_destroy_zone, malloc_zone_t *zone) {
COMMON_MALLOC_ENTER();
// We don't need to do anything here. We're not registering new zones, so we
// don't to unregister. Just un-mprotect and free() the zone.
- if (GetMacosVersion() >= MACOS_VERSION_LION) {
- uptr page_size = GetPageSizeCached();
- uptr allocated_size = RoundUpTo(sizeof(sanitizer_zone), page_size);
- mprotect(zone, allocated_size, PROT_READ | PROT_WRITE);
- }
+ uptr page_size = GetPageSizeCached();
+ uptr allocated_size = RoundUpTo(sizeof(sanitizer_zone), page_size);
+ mprotect(zone, allocated_size, PROT_READ | PROT_WRITE);
if (zone->zone_name) {
COMMON_MALLOC_FREE((void *)zone->zone_name);
}
diff --git a/libsanitizer/sanitizer_common/sanitizer_netbsd.cpp b/libsanitizer/sanitizer_common/sanitizer_netbsd.cpp
index 4e74f6a3b51..d9aff51d8ae 100644
--- a/libsanitizer/sanitizer_common/sanitizer_netbsd.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_netbsd.cpp
@@ -95,7 +95,7 @@ static void *GetRealLibcAddress(const char *symbol) {
// --------------- sanitizer_libc.h
uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd,
- OFF_T offset) {
+ u64 offset) {
CHECK(&__mmap);
return (uptr)__mmap(addr, length, prot, flags, fd, 0, offset);
}
@@ -265,6 +265,11 @@ uptr internal_getppid() {
return _REAL(getppid);
}
+int internal_dlinfo(void *handle, int request, void *p) {
+ DEFINE__REAL(int, dlinfo, void *a, int b, void *c);
+ return _REAL(dlinfo, handle, request, p);
+}
+
uptr internal_getdents(fd_t fd, void *dirp, unsigned int count) {
DEFINE__REAL(int, __getdents30, int a, void *b, size_t c);
return _REAL(__getdents30, fd, dirp, count);
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h b/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h
index 61a6b82ef81..9dd6d285f59 100644
--- a/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h
+++ b/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h
@@ -90,6 +90,24 @@
# define SI_IOS 0
#endif
+#if SANITIZER_IOSSIM
+# define SI_IOSSIM 1
+#else
+# define SI_IOSSIM 0
+#endif
+
+#if SANITIZER_WATCHOS
+# define SI_WATCHOS 1
+#else
+# define SI_WATCHOS 0
+#endif
+
+#if SANITIZER_TVOS
+# define SI_TVOS 1
+#else
+# define SI_TVOS 0
+#endif
+
#if SANITIZER_FUCHSIA
# define SI_NOT_FUCHSIA 0
#else
@@ -575,5 +593,11 @@
#define SANITIZER_INTERCEPT_ATEXIT SI_NETBSD
#define SANITIZER_INTERCEPT_PTHREAD_ATFORK SI_NETBSD
#define SANITIZER_INTERCEPT_GETENTROPY SI_FREEBSD
+#define SANITIZER_INTERCEPT_QSORT \
+ (SI_POSIX && !SI_IOSSIM && !SI_WATCHOS && !SI_TVOS && !SI_ANDROID)
+#define SANITIZER_INTERCEPT_QSORT_R (SI_LINUX && !SI_ANDROID)
+#define SANITIZER_INTERCEPT_SIGALTSTACK SI_POSIX
+#define SANITIZER_INTERCEPT_UNAME (SI_POSIX && !SI_FREEBSD)
+#define SANITIZER_INTERCEPT___XUNAME SI_FREEBSD
#endif // #ifndef SANITIZER_PLATFORM_INTERCEPTORS_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.cpp b/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.cpp
index 2d1bb1a12da..dcc6c71c07d 100644
--- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.cpp
@@ -15,342 +15,348 @@
#if SANITIZER_FREEBSD
+#include <sys/capsicum.h>
+#include <sys/consio.h>
+#include <sys/filio.h>
+#include <sys/ipc.h>
+#include <sys/kbio.h>
+#include <sys/link_elf.h>
+#include <sys/mman.h>
+#include <sys/mount.h>
+#include <sys/mqueue.h>
+#include <sys/msg.h>
+#include <sys/mtio.h>
+#include <sys/ptrace.h>
+#include <sys/resource.h>
+#include <sys/signal.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/soundcard.h>
+#include <sys/stat.h>
+#include <sys/statvfs.h>
+#include <sys/time.h>
+#include <sys/timeb.h>
+#include <sys/times.h>
+#include <sys/timespec.h>
+#include <sys/types.h>
+#include <sys/ucontext.h>
+#include <sys/utsname.h>
+//
#include <arpa/inet.h>
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/ppp_defs.h>
+#include <net/route.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <netinet/ip_mroute.h>
+//
#include <dirent.h>
-#include <fts.h>
+#include <dlfcn.h>
#include <fstab.h>
+#include <fts.h>
+#include <glob.h>
#include <grp.h>
+#include <ifaddrs.h>
#include <limits.h>
-#include <net/if.h>
-#include <netdb.h>
#include <poll.h>
#include <pthread.h>
#include <pwd.h>
#include <regex.h>
+#include <semaphore.h>
#include <signal.h>
#include <stddef.h>
-#include <sys/mman.h>
-#include <sys/capsicum.h>
-#include <sys/resource.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/times.h>
-#include <sys/types.h>
-#include <sys/utsname.h>
-#include <termios.h>
-#include <time.h>
-
-#include <net/route.h>
-#include <sys/mount.h>
-#include <sys/sockio.h>
-#include <sys/socket.h>
-#include <sys/filio.h>
-#include <sys/signal.h>
-#include <sys/timespec.h>
-#include <sys/timeb.h>
-#include <sys/mqueue.h>
-#include <sys/msg.h>
-#include <sys/ipc.h>
-#include <sys/msg.h>
-#include <sys/statvfs.h>
-#include <sys/soundcard.h>
-#include <sys/mtio.h>
-#include <sys/consio.h>
-#include <sys/kbio.h>
-#include <sys/link_elf.h>
-#include <netinet/ip_mroute.h>
-#include <netinet/in.h>
-#include <net/ethernet.h>
-#include <net/ppp_defs.h>
-#include <glob.h>
#include <stdio.h>
#include <stringlist.h>
#include <term.h>
+#include <termios.h>
+#include <time.h>
+#include <utime.h>
#include <utmpx.h>
-#include <wchar.h>
#include <vis.h>
+#include <wchar.h>
+#include <wordexp.h>
#define _KERNEL // to declare 'shminfo' structure
-# include <sys/shm.h>
+#include <sys/shm.h>
#undef _KERNEL
#undef INLINE // to avoid clashes with sanitizers' definitions
#undef IOC_DIRMASK
-# include <utime.h>
-# include <sys/ptrace.h>
-# include <semaphore.h>
-
-#include <ifaddrs.h>
-#include <sys/ucontext.h>
-#include <wordexp.h>
-
// Include these after system headers to avoid name clashes and ambiguities.
#include "sanitizer_internal_defs.h"
+#include "sanitizer_libc.h"
#include "sanitizer_platform_limits_freebsd.h"
namespace __sanitizer {
- unsigned struct_cap_rights_sz = sizeof(cap_rights_t);
- unsigned struct_utsname_sz = sizeof(struct utsname);
- unsigned struct_stat_sz = sizeof(struct stat);
- unsigned struct_rusage_sz = sizeof(struct rusage);
- unsigned struct_tm_sz = sizeof(struct tm);
- unsigned struct_passwd_sz = sizeof(struct passwd);
- unsigned struct_group_sz = sizeof(struct group);
- unsigned siginfo_t_sz = sizeof(siginfo_t);
- unsigned struct_sigaction_sz = sizeof(struct sigaction);
- unsigned struct_itimerval_sz = sizeof(struct itimerval);
- unsigned pthread_t_sz = sizeof(pthread_t);
- unsigned pthread_mutex_t_sz = sizeof(pthread_mutex_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);
- unsigned gid_t_sz = sizeof(gid_t);
- unsigned fpos_t_sz = sizeof(fpos_t);
- unsigned mbstate_t_sz = sizeof(mbstate_t);
- unsigned sigset_t_sz = sizeof(sigset_t);
- unsigned struct_timezone_sz = sizeof(struct timezone);
- 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);
- unsigned struct_sockaddr_sz = sizeof(struct sockaddr);
- unsigned ucontext_t_sz = sizeof(ucontext_t);
- unsigned struct_rlimit_sz = sizeof(struct rlimit);
- unsigned struct_timespec_sz = sizeof(struct timespec);
- unsigned struct_utimbuf_sz = sizeof(struct utimbuf);
- unsigned struct_itimerspec_sz = sizeof(struct itimerspec);
- unsigned struct_timeb_sz = sizeof(struct timeb);
- unsigned struct_msqid_ds_sz = sizeof(struct msqid_ds);
- unsigned struct_mq_attr_sz = sizeof(struct mq_attr);
- unsigned struct_statvfs_sz = sizeof(struct statvfs);
- unsigned struct_shminfo_sz = sizeof(struct shminfo);
- unsigned struct_shm_info_sz = sizeof(struct shm_info);
- unsigned struct_regmatch_sz = sizeof(regmatch_t);
- unsigned struct_regex_sz = sizeof(regex_t);
- unsigned struct_fstab_sz = sizeof(struct fstab);
- unsigned struct_FTS_sz = sizeof(FTS);
- unsigned struct_FTSENT_sz = sizeof(FTSENT);
- unsigned struct_StringList_sz = sizeof(StringList);
-
- const uptr sig_ign = (uptr)SIG_IGN;
- const uptr sig_dfl = (uptr)SIG_DFL;
- const uptr sig_err = (uptr)SIG_ERR;
- const uptr sa_siginfo = (uptr)SA_SIGINFO;
-
- 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_STAT;
- unsigned struct_utmpx_sz = sizeof(struct utmpx);
-
- int map_fixed = MAP_FIXED;
-
- int af_inet = (int)AF_INET;
- int af_inet6 = (int)AF_INET6;
-
- uptr __sanitizer_in_addr_sz(int af) {
- if (af == AF_INET)
- return sizeof(struct in_addr);
- else if (af == AF_INET6)
- return sizeof(struct in6_addr);
- else
- return 0;
- }
-
- unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
- int glob_nomatch = GLOB_NOMATCH;
- int glob_altdirfunc = GLOB_ALTDIRFUNC;
-
- unsigned path_max = PATH_MAX;
-
- // ioctl arguments
- unsigned struct_ifreq_sz = sizeof(struct ifreq);
- unsigned struct_termios_sz = sizeof(struct termios);
- unsigned struct_winsize_sz = sizeof(struct winsize);
+void *__sanitizer_get_link_map_by_dlopen_handle(void *handle) {
+ void *p = nullptr;
+ return internal_dlinfo(handle, RTLD_DI_LINKMAP, &p) == 0 ? p : nullptr;
+}
+
+unsigned struct_cap_rights_sz = sizeof(cap_rights_t);
+unsigned struct_utsname_sz = sizeof(struct utsname);
+unsigned struct_stat_sz = sizeof(struct stat);
+unsigned struct_rusage_sz = sizeof(struct rusage);
+unsigned struct_tm_sz = sizeof(struct tm);
+unsigned struct_passwd_sz = sizeof(struct passwd);
+unsigned struct_group_sz = sizeof(struct group);
+unsigned siginfo_t_sz = sizeof(siginfo_t);
+unsigned struct_sigaction_sz = sizeof(struct sigaction);
+unsigned struct_stack_t_sz = sizeof(stack_t);
+unsigned struct_itimerval_sz = sizeof(struct itimerval);
+unsigned pthread_t_sz = sizeof(pthread_t);
+unsigned pthread_mutex_t_sz = sizeof(pthread_mutex_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);
+unsigned gid_t_sz = sizeof(gid_t);
+unsigned fpos_t_sz = sizeof(fpos_t);
+unsigned mbstate_t_sz = sizeof(mbstate_t);
+unsigned sigset_t_sz = sizeof(sigset_t);
+unsigned struct_timezone_sz = sizeof(struct timezone);
+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);
+unsigned struct_sockaddr_sz = sizeof(struct sockaddr);
+unsigned ucontext_t_sz = sizeof(ucontext_t);
+unsigned struct_rlimit_sz = sizeof(struct rlimit);
+unsigned struct_timespec_sz = sizeof(struct timespec);
+unsigned struct_utimbuf_sz = sizeof(struct utimbuf);
+unsigned struct_itimerspec_sz = sizeof(struct itimerspec);
+unsigned struct_timeb_sz = sizeof(struct timeb);
+unsigned struct_msqid_ds_sz = sizeof(struct msqid_ds);
+unsigned struct_mq_attr_sz = sizeof(struct mq_attr);
+unsigned struct_statvfs_sz = sizeof(struct statvfs);
+unsigned struct_shminfo_sz = sizeof(struct shminfo);
+unsigned struct_shm_info_sz = sizeof(struct shm_info);
+unsigned struct_regmatch_sz = sizeof(regmatch_t);
+unsigned struct_regex_sz = sizeof(regex_t);
+unsigned struct_fstab_sz = sizeof(struct fstab);
+unsigned struct_FTS_sz = sizeof(FTS);
+unsigned struct_FTSENT_sz = sizeof(FTSENT);
+unsigned struct_StringList_sz = sizeof(StringList);
+
+const uptr sig_ign = (uptr)SIG_IGN;
+const uptr sig_dfl = (uptr)SIG_DFL;
+const uptr sig_err = (uptr)SIG_ERR;
+const uptr sa_siginfo = (uptr)SA_SIGINFO;
+
+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_STAT;
+unsigned struct_utmpx_sz = sizeof(struct utmpx);
+
+int map_fixed = MAP_FIXED;
+
+int af_inet = (int)AF_INET;
+int af_inet6 = (int)AF_INET6;
+
+uptr __sanitizer_in_addr_sz(int af) {
+ if (af == AF_INET)
+ return sizeof(struct in_addr);
+ else if (af == AF_INET6)
+ return sizeof(struct in6_addr);
+ else
+ return 0;
+}
+
+unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
+int glob_nomatch = GLOB_NOMATCH;
+int glob_altdirfunc = GLOB_ALTDIRFUNC;
+
+unsigned path_max = PATH_MAX;
+
+// ioctl arguments
+unsigned struct_ifreq_sz = sizeof(struct ifreq);
+unsigned struct_termios_sz = sizeof(struct termios);
+unsigned struct_winsize_sz = sizeof(struct winsize);
#if SOUND_VERSION >= 0x040000
- unsigned struct_copr_buffer_sz = 0;
- unsigned struct_copr_debug_buf_sz = 0;
- unsigned struct_copr_msg_sz = 0;
+unsigned struct_copr_buffer_sz = 0;
+unsigned struct_copr_debug_buf_sz = 0;
+unsigned struct_copr_msg_sz = 0;
#else
- unsigned struct_copr_buffer_sz = sizeof(struct copr_buffer);
- unsigned struct_copr_debug_buf_sz = sizeof(struct copr_debug_buf);
- unsigned struct_copr_msg_sz = sizeof(struct copr_msg);
+unsigned struct_copr_buffer_sz = sizeof(struct copr_buffer);
+unsigned struct_copr_debug_buf_sz = sizeof(struct copr_debug_buf);
+unsigned struct_copr_msg_sz = sizeof(struct copr_msg);
#endif
- unsigned struct_midi_info_sz = sizeof(struct midi_info);
- unsigned struct_mtget_sz = sizeof(struct mtget);
- unsigned struct_mtop_sz = sizeof(struct mtop);
- unsigned struct_sbi_instrument_sz = sizeof(struct sbi_instrument);
- unsigned struct_seq_event_rec_sz = sizeof(struct seq_event_rec);
- unsigned struct_synth_info_sz = sizeof(struct synth_info);
- unsigned struct_audio_buf_info_sz = sizeof(struct audio_buf_info);
- unsigned struct_ppp_stats_sz = sizeof(struct ppp_stats);
- unsigned struct_sioc_sg_req_sz = sizeof(struct sioc_sg_req);
- unsigned struct_sioc_vif_req_sz = sizeof(struct sioc_vif_req);
- const unsigned long __sanitizer_bufsiz = BUFSIZ;
-
- const unsigned IOCTL_NOT_PRESENT = 0;
-
- unsigned IOCTL_FIOASYNC = FIOASYNC;
- unsigned IOCTL_FIOCLEX = FIOCLEX;
- unsigned IOCTL_FIOGETOWN = FIOGETOWN;
- unsigned IOCTL_FIONBIO = FIONBIO;
- unsigned IOCTL_FIONCLEX = FIONCLEX;
- unsigned IOCTL_FIOSETOWN = FIOSETOWN;
- unsigned IOCTL_SIOCADDMULTI = SIOCADDMULTI;
- unsigned IOCTL_SIOCATMARK = SIOCATMARK;
- unsigned IOCTL_SIOCDELMULTI = SIOCDELMULTI;
- unsigned IOCTL_SIOCGIFADDR = SIOCGIFADDR;
- unsigned IOCTL_SIOCGIFBRDADDR = SIOCGIFBRDADDR;
- unsigned IOCTL_SIOCGIFCONF = SIOCGIFCONF;
- unsigned IOCTL_SIOCGIFDSTADDR = SIOCGIFDSTADDR;
- unsigned IOCTL_SIOCGIFFLAGS = SIOCGIFFLAGS;
- unsigned IOCTL_SIOCGIFMETRIC = SIOCGIFMETRIC;
- unsigned IOCTL_SIOCGIFMTU = SIOCGIFMTU;
- unsigned IOCTL_SIOCGIFNETMASK = SIOCGIFNETMASK;
- unsigned IOCTL_SIOCGPGRP = SIOCGPGRP;
- unsigned IOCTL_SIOCSIFADDR = SIOCSIFADDR;
- unsigned IOCTL_SIOCSIFBRDADDR = SIOCSIFBRDADDR;
- unsigned IOCTL_SIOCSIFDSTADDR = SIOCSIFDSTADDR;
- unsigned IOCTL_SIOCSIFFLAGS = SIOCSIFFLAGS;
- unsigned IOCTL_SIOCSIFMETRIC = SIOCSIFMETRIC;
- unsigned IOCTL_SIOCSIFMTU = SIOCSIFMTU;
- unsigned IOCTL_SIOCSIFNETMASK = SIOCSIFNETMASK;
- unsigned IOCTL_SIOCSPGRP = SIOCSPGRP;
- unsigned IOCTL_TIOCCONS = TIOCCONS;
- unsigned IOCTL_TIOCEXCL = TIOCEXCL;
- unsigned IOCTL_TIOCGETD = TIOCGETD;
- unsigned IOCTL_TIOCGPGRP = TIOCGPGRP;
- unsigned IOCTL_TIOCGWINSZ = TIOCGWINSZ;
- unsigned IOCTL_TIOCMBIC = TIOCMBIC;
- unsigned IOCTL_TIOCMBIS = TIOCMBIS;
- unsigned IOCTL_TIOCMGET = TIOCMGET;
- unsigned IOCTL_TIOCMSET = TIOCMSET;
- unsigned IOCTL_TIOCNOTTY = TIOCNOTTY;
- unsigned IOCTL_TIOCNXCL = TIOCNXCL;
- unsigned IOCTL_TIOCOUTQ = TIOCOUTQ;
- unsigned IOCTL_TIOCPKT = TIOCPKT;
- unsigned IOCTL_TIOCSCTTY = TIOCSCTTY;
- unsigned IOCTL_TIOCSETD = TIOCSETD;
- unsigned IOCTL_TIOCSPGRP = TIOCSPGRP;
- unsigned IOCTL_TIOCSTI = TIOCSTI;
- unsigned IOCTL_TIOCSWINSZ = TIOCSWINSZ;
- unsigned IOCTL_SIOCGETSGCNT = SIOCGETSGCNT;
- unsigned IOCTL_SIOCGETVIFCNT = SIOCGETVIFCNT;
- unsigned IOCTL_MTIOCGET = MTIOCGET;
- unsigned IOCTL_MTIOCTOP = MTIOCTOP;
- unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE = SNDCTL_DSP_GETBLKSIZE;
- unsigned IOCTL_SNDCTL_DSP_GETFMTS = SNDCTL_DSP_GETFMTS;
- unsigned IOCTL_SNDCTL_DSP_NONBLOCK = SNDCTL_DSP_NONBLOCK;
- unsigned IOCTL_SNDCTL_DSP_POST = SNDCTL_DSP_POST;
- unsigned IOCTL_SNDCTL_DSP_RESET = SNDCTL_DSP_RESET;
- unsigned IOCTL_SNDCTL_DSP_SETFMT = SNDCTL_DSP_SETFMT;
- unsigned IOCTL_SNDCTL_DSP_SETFRAGMENT = SNDCTL_DSP_SETFRAGMENT;
- unsigned IOCTL_SNDCTL_DSP_SPEED = SNDCTL_DSP_SPEED;
- unsigned IOCTL_SNDCTL_DSP_STEREO = SNDCTL_DSP_STEREO;
- unsigned IOCTL_SNDCTL_DSP_SUBDIVIDE = SNDCTL_DSP_SUBDIVIDE;
- unsigned IOCTL_SNDCTL_DSP_SYNC = SNDCTL_DSP_SYNC;
- unsigned IOCTL_SNDCTL_FM_4OP_ENABLE = SNDCTL_FM_4OP_ENABLE;
- unsigned IOCTL_SNDCTL_FM_LOAD_INSTR = SNDCTL_FM_LOAD_INSTR;
- unsigned IOCTL_SNDCTL_MIDI_INFO = SNDCTL_MIDI_INFO;
- unsigned IOCTL_SNDCTL_MIDI_PRETIME = SNDCTL_MIDI_PRETIME;
- unsigned IOCTL_SNDCTL_SEQ_CTRLRATE = SNDCTL_SEQ_CTRLRATE;
- unsigned IOCTL_SNDCTL_SEQ_GETINCOUNT = SNDCTL_SEQ_GETINCOUNT;
- unsigned IOCTL_SNDCTL_SEQ_GETOUTCOUNT = SNDCTL_SEQ_GETOUTCOUNT;
- unsigned IOCTL_SNDCTL_SEQ_NRMIDIS = SNDCTL_SEQ_NRMIDIS;
- unsigned IOCTL_SNDCTL_SEQ_NRSYNTHS = SNDCTL_SEQ_NRSYNTHS;
- unsigned IOCTL_SNDCTL_SEQ_OUTOFBAND = SNDCTL_SEQ_OUTOFBAND;
- unsigned IOCTL_SNDCTL_SEQ_PANIC = SNDCTL_SEQ_PANIC;
- unsigned IOCTL_SNDCTL_SEQ_PERCMODE = SNDCTL_SEQ_PERCMODE;
- unsigned IOCTL_SNDCTL_SEQ_RESET = SNDCTL_SEQ_RESET;
- unsigned IOCTL_SNDCTL_SEQ_RESETSAMPLES = SNDCTL_SEQ_RESETSAMPLES;
- unsigned IOCTL_SNDCTL_SEQ_SYNC = SNDCTL_SEQ_SYNC;
- unsigned IOCTL_SNDCTL_SEQ_TESTMIDI = SNDCTL_SEQ_TESTMIDI;
- unsigned IOCTL_SNDCTL_SEQ_THRESHOLD = SNDCTL_SEQ_THRESHOLD;
- unsigned IOCTL_SNDCTL_SYNTH_INFO = SNDCTL_SYNTH_INFO;
- unsigned IOCTL_SNDCTL_SYNTH_MEMAVL = SNDCTL_SYNTH_MEMAVL;
- unsigned IOCTL_SNDCTL_TMR_CONTINUE = SNDCTL_TMR_CONTINUE;
- unsigned IOCTL_SNDCTL_TMR_METRONOME = SNDCTL_TMR_METRONOME;
- unsigned IOCTL_SNDCTL_TMR_SELECT = SNDCTL_TMR_SELECT;
- unsigned IOCTL_SNDCTL_TMR_SOURCE = SNDCTL_TMR_SOURCE;
- unsigned IOCTL_SNDCTL_TMR_START = SNDCTL_TMR_START;
- unsigned IOCTL_SNDCTL_TMR_STOP = SNDCTL_TMR_STOP;
- unsigned IOCTL_SNDCTL_TMR_TEMPO = SNDCTL_TMR_TEMPO;
- unsigned IOCTL_SNDCTL_TMR_TIMEBASE = SNDCTL_TMR_TIMEBASE;
- unsigned IOCTL_SOUND_MIXER_READ_ALTPCM = SOUND_MIXER_READ_ALTPCM;
- unsigned IOCTL_SOUND_MIXER_READ_BASS = SOUND_MIXER_READ_BASS;
- unsigned IOCTL_SOUND_MIXER_READ_CAPS = SOUND_MIXER_READ_CAPS;
- unsigned IOCTL_SOUND_MIXER_READ_CD = SOUND_MIXER_READ_CD;
- unsigned IOCTL_SOUND_MIXER_READ_DEVMASK = SOUND_MIXER_READ_DEVMASK;
- unsigned IOCTL_SOUND_MIXER_READ_ENHANCE = SOUND_MIXER_READ_ENHANCE;
- unsigned IOCTL_SOUND_MIXER_READ_IGAIN = SOUND_MIXER_READ_IGAIN;
- unsigned IOCTL_SOUND_MIXER_READ_IMIX = SOUND_MIXER_READ_IMIX;
- unsigned IOCTL_SOUND_MIXER_READ_LINE = SOUND_MIXER_READ_LINE;
- unsigned IOCTL_SOUND_MIXER_READ_LINE1 = SOUND_MIXER_READ_LINE1;
- unsigned IOCTL_SOUND_MIXER_READ_LINE2 = SOUND_MIXER_READ_LINE2;
- unsigned IOCTL_SOUND_MIXER_READ_LINE3 = SOUND_MIXER_READ_LINE3;
- unsigned IOCTL_SOUND_MIXER_READ_LOUD = SOUND_MIXER_READ_LOUD;
- unsigned IOCTL_SOUND_MIXER_READ_MIC = SOUND_MIXER_READ_MIC;
- unsigned IOCTL_SOUND_MIXER_READ_MUTE = SOUND_MIXER_READ_MUTE;
- unsigned IOCTL_SOUND_MIXER_READ_OGAIN = SOUND_MIXER_READ_OGAIN;
- unsigned IOCTL_SOUND_MIXER_READ_PCM = SOUND_MIXER_READ_PCM;
- unsigned IOCTL_SOUND_MIXER_READ_RECLEV = SOUND_MIXER_READ_RECLEV;
- unsigned IOCTL_SOUND_MIXER_READ_RECMASK = SOUND_MIXER_READ_RECMASK;
- unsigned IOCTL_SOUND_MIXER_READ_RECSRC = SOUND_MIXER_READ_RECSRC;
- unsigned IOCTL_SOUND_MIXER_READ_SPEAKER = SOUND_MIXER_READ_SPEAKER;
- unsigned IOCTL_SOUND_MIXER_READ_STEREODEVS = SOUND_MIXER_READ_STEREODEVS;
- unsigned IOCTL_SOUND_MIXER_READ_SYNTH = SOUND_MIXER_READ_SYNTH;
- unsigned IOCTL_SOUND_MIXER_READ_TREBLE = SOUND_MIXER_READ_TREBLE;
- unsigned IOCTL_SOUND_MIXER_READ_VOLUME = SOUND_MIXER_READ_VOLUME;
- unsigned IOCTL_SOUND_MIXER_WRITE_ALTPCM = SOUND_MIXER_WRITE_ALTPCM;
- unsigned IOCTL_SOUND_MIXER_WRITE_BASS = SOUND_MIXER_WRITE_BASS;
- unsigned IOCTL_SOUND_MIXER_WRITE_CD = SOUND_MIXER_WRITE_CD;
- unsigned IOCTL_SOUND_MIXER_WRITE_ENHANCE = SOUND_MIXER_WRITE_ENHANCE;
- unsigned IOCTL_SOUND_MIXER_WRITE_IGAIN = SOUND_MIXER_WRITE_IGAIN;
- unsigned IOCTL_SOUND_MIXER_WRITE_IMIX = SOUND_MIXER_WRITE_IMIX;
- unsigned IOCTL_SOUND_MIXER_WRITE_LINE = SOUND_MIXER_WRITE_LINE;
- unsigned IOCTL_SOUND_MIXER_WRITE_LINE1 = SOUND_MIXER_WRITE_LINE1;
- unsigned IOCTL_SOUND_MIXER_WRITE_LINE2 = SOUND_MIXER_WRITE_LINE2;
- unsigned IOCTL_SOUND_MIXER_WRITE_LINE3 = SOUND_MIXER_WRITE_LINE3;
- unsigned IOCTL_SOUND_MIXER_WRITE_LOUD = SOUND_MIXER_WRITE_LOUD;
- unsigned IOCTL_SOUND_MIXER_WRITE_MIC = SOUND_MIXER_WRITE_MIC;
- unsigned IOCTL_SOUND_MIXER_WRITE_MUTE = SOUND_MIXER_WRITE_MUTE;
- unsigned IOCTL_SOUND_MIXER_WRITE_OGAIN = SOUND_MIXER_WRITE_OGAIN;
- unsigned IOCTL_SOUND_MIXER_WRITE_PCM = SOUND_MIXER_WRITE_PCM;
- unsigned IOCTL_SOUND_MIXER_WRITE_RECLEV = SOUND_MIXER_WRITE_RECLEV;
- unsigned IOCTL_SOUND_MIXER_WRITE_RECSRC = SOUND_MIXER_WRITE_RECSRC;
- unsigned IOCTL_SOUND_MIXER_WRITE_SPEAKER = SOUND_MIXER_WRITE_SPEAKER;
- unsigned IOCTL_SOUND_MIXER_WRITE_SYNTH = SOUND_MIXER_WRITE_SYNTH;
- unsigned IOCTL_SOUND_MIXER_WRITE_TREBLE = SOUND_MIXER_WRITE_TREBLE;
- unsigned IOCTL_SOUND_MIXER_WRITE_VOLUME = SOUND_MIXER_WRITE_VOLUME;
- unsigned IOCTL_VT_ACTIVATE = VT_ACTIVATE;
- unsigned IOCTL_VT_GETMODE = VT_GETMODE;
- unsigned IOCTL_VT_OPENQRY = VT_OPENQRY;
- unsigned IOCTL_VT_RELDISP = VT_RELDISP;
- unsigned IOCTL_VT_SETMODE = VT_SETMODE;
- unsigned IOCTL_VT_WAITACTIVE = VT_WAITACTIVE;
- unsigned IOCTL_GIO_SCRNMAP = GIO_SCRNMAP;
- unsigned IOCTL_KDDISABIO = KDDISABIO;
- unsigned IOCTL_KDENABIO = KDENABIO;
- unsigned IOCTL_KDGETLED = KDGETLED;
- unsigned IOCTL_KDGETMODE = KDGETMODE;
- unsigned IOCTL_KDGKBMODE = KDGKBMODE;
- unsigned IOCTL_KDGKBTYPE = KDGKBTYPE;
- unsigned IOCTL_KDMKTONE = KDMKTONE;
- unsigned IOCTL_KDSETLED = KDSETLED;
- unsigned IOCTL_KDSETMODE = KDSETMODE;
- unsigned IOCTL_KDSKBMODE = KDSKBMODE;
- unsigned IOCTL_KIOCSOUND = KIOCSOUND;
- unsigned IOCTL_PIO_SCRNMAP = PIO_SCRNMAP;
- unsigned IOCTL_SNDCTL_DSP_GETISPACE = SNDCTL_DSP_GETISPACE;
-
- const int si_SEGV_MAPERR = SEGV_MAPERR;
- const int si_SEGV_ACCERR = SEGV_ACCERR;
- const int unvis_valid = UNVIS_VALID;
- const int unvis_validpush = UNVIS_VALIDPUSH;
-} // namespace __sanitizer
+unsigned struct_midi_info_sz = sizeof(struct midi_info);
+unsigned struct_mtget_sz = sizeof(struct mtget);
+unsigned struct_mtop_sz = sizeof(struct mtop);
+unsigned struct_sbi_instrument_sz = sizeof(struct sbi_instrument);
+unsigned struct_seq_event_rec_sz = sizeof(struct seq_event_rec);
+unsigned struct_synth_info_sz = sizeof(struct synth_info);
+unsigned struct_audio_buf_info_sz = sizeof(struct audio_buf_info);
+unsigned struct_ppp_stats_sz = sizeof(struct ppp_stats);
+unsigned struct_sioc_sg_req_sz = sizeof(struct sioc_sg_req);
+unsigned struct_sioc_vif_req_sz = sizeof(struct sioc_vif_req);
+const unsigned long __sanitizer_bufsiz = BUFSIZ;
+
+const unsigned IOCTL_NOT_PRESENT = 0;
+
+unsigned IOCTL_FIOASYNC = FIOASYNC;
+unsigned IOCTL_FIOCLEX = FIOCLEX;
+unsigned IOCTL_FIOGETOWN = FIOGETOWN;
+unsigned IOCTL_FIONBIO = FIONBIO;
+unsigned IOCTL_FIONCLEX = FIONCLEX;
+unsigned IOCTL_FIOSETOWN = FIOSETOWN;
+unsigned IOCTL_SIOCADDMULTI = SIOCADDMULTI;
+unsigned IOCTL_SIOCATMARK = SIOCATMARK;
+unsigned IOCTL_SIOCDELMULTI = SIOCDELMULTI;
+unsigned IOCTL_SIOCGIFADDR = SIOCGIFADDR;
+unsigned IOCTL_SIOCGIFBRDADDR = SIOCGIFBRDADDR;
+unsigned IOCTL_SIOCGIFCONF = SIOCGIFCONF;
+unsigned IOCTL_SIOCGIFDSTADDR = SIOCGIFDSTADDR;
+unsigned IOCTL_SIOCGIFFLAGS = SIOCGIFFLAGS;
+unsigned IOCTL_SIOCGIFMETRIC = SIOCGIFMETRIC;
+unsigned IOCTL_SIOCGIFMTU = SIOCGIFMTU;
+unsigned IOCTL_SIOCGIFNETMASK = SIOCGIFNETMASK;
+unsigned IOCTL_SIOCGPGRP = SIOCGPGRP;
+unsigned IOCTL_SIOCSIFADDR = SIOCSIFADDR;
+unsigned IOCTL_SIOCSIFBRDADDR = SIOCSIFBRDADDR;
+unsigned IOCTL_SIOCSIFDSTADDR = SIOCSIFDSTADDR;
+unsigned IOCTL_SIOCSIFFLAGS = SIOCSIFFLAGS;
+unsigned IOCTL_SIOCSIFMETRIC = SIOCSIFMETRIC;
+unsigned IOCTL_SIOCSIFMTU = SIOCSIFMTU;
+unsigned IOCTL_SIOCSIFNETMASK = SIOCSIFNETMASK;
+unsigned IOCTL_SIOCSPGRP = SIOCSPGRP;
+unsigned IOCTL_TIOCCONS = TIOCCONS;
+unsigned IOCTL_TIOCEXCL = TIOCEXCL;
+unsigned IOCTL_TIOCGETD = TIOCGETD;
+unsigned IOCTL_TIOCGPGRP = TIOCGPGRP;
+unsigned IOCTL_TIOCGWINSZ = TIOCGWINSZ;
+unsigned IOCTL_TIOCMBIC = TIOCMBIC;
+unsigned IOCTL_TIOCMBIS = TIOCMBIS;
+unsigned IOCTL_TIOCMGET = TIOCMGET;
+unsigned IOCTL_TIOCMSET = TIOCMSET;
+unsigned IOCTL_TIOCNOTTY = TIOCNOTTY;
+unsigned IOCTL_TIOCNXCL = TIOCNXCL;
+unsigned IOCTL_TIOCOUTQ = TIOCOUTQ;
+unsigned IOCTL_TIOCPKT = TIOCPKT;
+unsigned IOCTL_TIOCSCTTY = TIOCSCTTY;
+unsigned IOCTL_TIOCSETD = TIOCSETD;
+unsigned IOCTL_TIOCSPGRP = TIOCSPGRP;
+unsigned IOCTL_TIOCSTI = TIOCSTI;
+unsigned IOCTL_TIOCSWINSZ = TIOCSWINSZ;
+unsigned IOCTL_SIOCGETSGCNT = SIOCGETSGCNT;
+unsigned IOCTL_SIOCGETVIFCNT = SIOCGETVIFCNT;
+unsigned IOCTL_MTIOCGET = MTIOCGET;
+unsigned IOCTL_MTIOCTOP = MTIOCTOP;
+unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE = SNDCTL_DSP_GETBLKSIZE;
+unsigned IOCTL_SNDCTL_DSP_GETFMTS = SNDCTL_DSP_GETFMTS;
+unsigned IOCTL_SNDCTL_DSP_NONBLOCK = SNDCTL_DSP_NONBLOCK;
+unsigned IOCTL_SNDCTL_DSP_POST = SNDCTL_DSP_POST;
+unsigned IOCTL_SNDCTL_DSP_RESET = SNDCTL_DSP_RESET;
+unsigned IOCTL_SNDCTL_DSP_SETFMT = SNDCTL_DSP_SETFMT;
+unsigned IOCTL_SNDCTL_DSP_SETFRAGMENT = SNDCTL_DSP_SETFRAGMENT;
+unsigned IOCTL_SNDCTL_DSP_SPEED = SNDCTL_DSP_SPEED;
+unsigned IOCTL_SNDCTL_DSP_STEREO = SNDCTL_DSP_STEREO;
+unsigned IOCTL_SNDCTL_DSP_SUBDIVIDE = SNDCTL_DSP_SUBDIVIDE;
+unsigned IOCTL_SNDCTL_DSP_SYNC = SNDCTL_DSP_SYNC;
+unsigned IOCTL_SNDCTL_FM_4OP_ENABLE = SNDCTL_FM_4OP_ENABLE;
+unsigned IOCTL_SNDCTL_FM_LOAD_INSTR = SNDCTL_FM_LOAD_INSTR;
+unsigned IOCTL_SNDCTL_MIDI_INFO = SNDCTL_MIDI_INFO;
+unsigned IOCTL_SNDCTL_MIDI_PRETIME = SNDCTL_MIDI_PRETIME;
+unsigned IOCTL_SNDCTL_SEQ_CTRLRATE = SNDCTL_SEQ_CTRLRATE;
+unsigned IOCTL_SNDCTL_SEQ_GETINCOUNT = SNDCTL_SEQ_GETINCOUNT;
+unsigned IOCTL_SNDCTL_SEQ_GETOUTCOUNT = SNDCTL_SEQ_GETOUTCOUNT;
+unsigned IOCTL_SNDCTL_SEQ_NRMIDIS = SNDCTL_SEQ_NRMIDIS;
+unsigned IOCTL_SNDCTL_SEQ_NRSYNTHS = SNDCTL_SEQ_NRSYNTHS;
+unsigned IOCTL_SNDCTL_SEQ_OUTOFBAND = SNDCTL_SEQ_OUTOFBAND;
+unsigned IOCTL_SNDCTL_SEQ_PANIC = SNDCTL_SEQ_PANIC;
+unsigned IOCTL_SNDCTL_SEQ_PERCMODE = SNDCTL_SEQ_PERCMODE;
+unsigned IOCTL_SNDCTL_SEQ_RESET = SNDCTL_SEQ_RESET;
+unsigned IOCTL_SNDCTL_SEQ_RESETSAMPLES = SNDCTL_SEQ_RESETSAMPLES;
+unsigned IOCTL_SNDCTL_SEQ_SYNC = SNDCTL_SEQ_SYNC;
+unsigned IOCTL_SNDCTL_SEQ_TESTMIDI = SNDCTL_SEQ_TESTMIDI;
+unsigned IOCTL_SNDCTL_SEQ_THRESHOLD = SNDCTL_SEQ_THRESHOLD;
+unsigned IOCTL_SNDCTL_SYNTH_INFO = SNDCTL_SYNTH_INFO;
+unsigned IOCTL_SNDCTL_SYNTH_MEMAVL = SNDCTL_SYNTH_MEMAVL;
+unsigned IOCTL_SNDCTL_TMR_CONTINUE = SNDCTL_TMR_CONTINUE;
+unsigned IOCTL_SNDCTL_TMR_METRONOME = SNDCTL_TMR_METRONOME;
+unsigned IOCTL_SNDCTL_TMR_SELECT = SNDCTL_TMR_SELECT;
+unsigned IOCTL_SNDCTL_TMR_SOURCE = SNDCTL_TMR_SOURCE;
+unsigned IOCTL_SNDCTL_TMR_START = SNDCTL_TMR_START;
+unsigned IOCTL_SNDCTL_TMR_STOP = SNDCTL_TMR_STOP;
+unsigned IOCTL_SNDCTL_TMR_TEMPO = SNDCTL_TMR_TEMPO;
+unsigned IOCTL_SNDCTL_TMR_TIMEBASE = SNDCTL_TMR_TIMEBASE;
+unsigned IOCTL_SOUND_MIXER_READ_ALTPCM = SOUND_MIXER_READ_ALTPCM;
+unsigned IOCTL_SOUND_MIXER_READ_BASS = SOUND_MIXER_READ_BASS;
+unsigned IOCTL_SOUND_MIXER_READ_CAPS = SOUND_MIXER_READ_CAPS;
+unsigned IOCTL_SOUND_MIXER_READ_CD = SOUND_MIXER_READ_CD;
+unsigned IOCTL_SOUND_MIXER_READ_DEVMASK = SOUND_MIXER_READ_DEVMASK;
+unsigned IOCTL_SOUND_MIXER_READ_ENHANCE = SOUND_MIXER_READ_ENHANCE;
+unsigned IOCTL_SOUND_MIXER_READ_IGAIN = SOUND_MIXER_READ_IGAIN;
+unsigned IOCTL_SOUND_MIXER_READ_IMIX = SOUND_MIXER_READ_IMIX;
+unsigned IOCTL_SOUND_MIXER_READ_LINE = SOUND_MIXER_READ_LINE;
+unsigned IOCTL_SOUND_MIXER_READ_LINE1 = SOUND_MIXER_READ_LINE1;
+unsigned IOCTL_SOUND_MIXER_READ_LINE2 = SOUND_MIXER_READ_LINE2;
+unsigned IOCTL_SOUND_MIXER_READ_LINE3 = SOUND_MIXER_READ_LINE3;
+unsigned IOCTL_SOUND_MIXER_READ_LOUD = SOUND_MIXER_READ_LOUD;
+unsigned IOCTL_SOUND_MIXER_READ_MIC = SOUND_MIXER_READ_MIC;
+unsigned IOCTL_SOUND_MIXER_READ_MUTE = SOUND_MIXER_READ_MUTE;
+unsigned IOCTL_SOUND_MIXER_READ_OGAIN = SOUND_MIXER_READ_OGAIN;
+unsigned IOCTL_SOUND_MIXER_READ_PCM = SOUND_MIXER_READ_PCM;
+unsigned IOCTL_SOUND_MIXER_READ_RECLEV = SOUND_MIXER_READ_RECLEV;
+unsigned IOCTL_SOUND_MIXER_READ_RECMASK = SOUND_MIXER_READ_RECMASK;
+unsigned IOCTL_SOUND_MIXER_READ_RECSRC = SOUND_MIXER_READ_RECSRC;
+unsigned IOCTL_SOUND_MIXER_READ_SPEAKER = SOUND_MIXER_READ_SPEAKER;
+unsigned IOCTL_SOUND_MIXER_READ_STEREODEVS = SOUND_MIXER_READ_STEREODEVS;
+unsigned IOCTL_SOUND_MIXER_READ_SYNTH = SOUND_MIXER_READ_SYNTH;
+unsigned IOCTL_SOUND_MIXER_READ_TREBLE = SOUND_MIXER_READ_TREBLE;
+unsigned IOCTL_SOUND_MIXER_READ_VOLUME = SOUND_MIXER_READ_VOLUME;
+unsigned IOCTL_SOUND_MIXER_WRITE_ALTPCM = SOUND_MIXER_WRITE_ALTPCM;
+unsigned IOCTL_SOUND_MIXER_WRITE_BASS = SOUND_MIXER_WRITE_BASS;
+unsigned IOCTL_SOUND_MIXER_WRITE_CD = SOUND_MIXER_WRITE_CD;
+unsigned IOCTL_SOUND_MIXER_WRITE_ENHANCE = SOUND_MIXER_WRITE_ENHANCE;
+unsigned IOCTL_SOUND_MIXER_WRITE_IGAIN = SOUND_MIXER_WRITE_IGAIN;
+unsigned IOCTL_SOUND_MIXER_WRITE_IMIX = SOUND_MIXER_WRITE_IMIX;
+unsigned IOCTL_SOUND_MIXER_WRITE_LINE = SOUND_MIXER_WRITE_LINE;
+unsigned IOCTL_SOUND_MIXER_WRITE_LINE1 = SOUND_MIXER_WRITE_LINE1;
+unsigned IOCTL_SOUND_MIXER_WRITE_LINE2 = SOUND_MIXER_WRITE_LINE2;
+unsigned IOCTL_SOUND_MIXER_WRITE_LINE3 = SOUND_MIXER_WRITE_LINE3;
+unsigned IOCTL_SOUND_MIXER_WRITE_LOUD = SOUND_MIXER_WRITE_LOUD;
+unsigned IOCTL_SOUND_MIXER_WRITE_MIC = SOUND_MIXER_WRITE_MIC;
+unsigned IOCTL_SOUND_MIXER_WRITE_MUTE = SOUND_MIXER_WRITE_MUTE;
+unsigned IOCTL_SOUND_MIXER_WRITE_OGAIN = SOUND_MIXER_WRITE_OGAIN;
+unsigned IOCTL_SOUND_MIXER_WRITE_PCM = SOUND_MIXER_WRITE_PCM;
+unsigned IOCTL_SOUND_MIXER_WRITE_RECLEV = SOUND_MIXER_WRITE_RECLEV;
+unsigned IOCTL_SOUND_MIXER_WRITE_RECSRC = SOUND_MIXER_WRITE_RECSRC;
+unsigned IOCTL_SOUND_MIXER_WRITE_SPEAKER = SOUND_MIXER_WRITE_SPEAKER;
+unsigned IOCTL_SOUND_MIXER_WRITE_SYNTH = SOUND_MIXER_WRITE_SYNTH;
+unsigned IOCTL_SOUND_MIXER_WRITE_TREBLE = SOUND_MIXER_WRITE_TREBLE;
+unsigned IOCTL_SOUND_MIXER_WRITE_VOLUME = SOUND_MIXER_WRITE_VOLUME;
+unsigned IOCTL_VT_ACTIVATE = VT_ACTIVATE;
+unsigned IOCTL_VT_GETMODE = VT_GETMODE;
+unsigned IOCTL_VT_OPENQRY = VT_OPENQRY;
+unsigned IOCTL_VT_RELDISP = VT_RELDISP;
+unsigned IOCTL_VT_SETMODE = VT_SETMODE;
+unsigned IOCTL_VT_WAITACTIVE = VT_WAITACTIVE;
+unsigned IOCTL_GIO_SCRNMAP = GIO_SCRNMAP;
+unsigned IOCTL_KDDISABIO = KDDISABIO;
+unsigned IOCTL_KDENABIO = KDENABIO;
+unsigned IOCTL_KDGETLED = KDGETLED;
+unsigned IOCTL_KDGETMODE = KDGETMODE;
+unsigned IOCTL_KDGKBMODE = KDGKBMODE;
+unsigned IOCTL_KDGKBTYPE = KDGKBTYPE;
+unsigned IOCTL_KDMKTONE = KDMKTONE;
+unsigned IOCTL_KDSETLED = KDSETLED;
+unsigned IOCTL_KDSETMODE = KDSETMODE;
+unsigned IOCTL_KDSKBMODE = KDSKBMODE;
+unsigned IOCTL_KIOCSOUND = KIOCSOUND;
+unsigned IOCTL_PIO_SCRNMAP = PIO_SCRNMAP;
+unsigned IOCTL_SNDCTL_DSP_GETISPACE = SNDCTL_DSP_GETISPACE;
+
+const int si_SEGV_MAPERR = SEGV_MAPERR;
+const int si_SEGV_ACCERR = SEGV_ACCERR;
+const int unvis_valid = UNVIS_VALID;
+const int unvis_validpush = UNVIS_VALIDPUSH;
+} // namespace __sanitizer
using namespace __sanitizer;
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.h b/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.h
index 71cf5b9c357..5e0ca9c7d78 100644
--- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.h
+++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.h
@@ -18,18 +18,17 @@
#include "sanitizer_internal_defs.h"
#include "sanitizer_platform.h"
-
#include "sanitizer_platform_limits_posix.h"
-// FreeBSD's dlopen() returns a pointer to an Obj_Entry structure that
-// incorporates the map structure.
-# define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \
- ((link_map*)((handle) == nullptr ? nullptr : ((char*)(handle) + 560)))
// Get sys/_types.h, because that tells us whether 64-bit inodes are
// used in struct dirent below.
#include <sys/_types.h>
namespace __sanitizer {
+void *__sanitizer_get_link_map_by_dlopen_handle(void *handle);
+#define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \
+ (link_map *)__sanitizer_get_link_map_by_dlopen_handle(handle)
+
extern unsigned struct_utsname_sz;
extern unsigned struct_stat_sz;
#if defined(__powerpc64__)
@@ -53,6 +52,7 @@ extern unsigned struct_timezone_sz;
extern unsigned struct_tms_sz;
extern unsigned struct_itimerspec_sz;
extern unsigned struct_sigevent_sz;
+extern unsigned struct_stack_t_sz;
extern unsigned struct_sched_param_sz;
extern unsigned struct_statfs64_sz;
extern unsigned struct_statfs_sz;
@@ -147,7 +147,7 @@ struct __sanitizer_ifaddrs {
unsigned int ifa_flags;
void *ifa_addr; // (struct sockaddr *)
void *ifa_netmask; // (struct sockaddr *)
-# undef ifa_dstaddr
+#undef ifa_dstaddr
void *ifa_dstaddr; // (struct sockaddr *)
void *ifa_data;
};
@@ -630,27 +630,27 @@ extern unsigned struct_cap_rights_sz;
extern unsigned struct_fstab_sz;
extern unsigned struct_StringList_sz;
-} // namespace __sanitizer
+} // 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) == \
+#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) == \
+#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))
#define SIGACTION_SYMNAME sigaction
#endif
-#endif // SANITIZER_FREEBSD
+#endif // SANITIZER_FREEBSD
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cpp b/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cpp
index f22f5039128..c51327e1269 100644
--- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cpp
@@ -26,12 +26,9 @@
// 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. Beware that with <sys/stat.h>, struct stat
-// takes the form of struct stat64 on 32-bit platforms if _FILE_OFFSET_BITS=64.
-// Also, for some platforms (e.g. mips) there are additional members in the
-// <sys/stat.h> struct stat:s.
+// fine with newer headers, too.
#include <linux/posix_types.h>
-#if defined(__x86_64__)
+#if defined(__x86_64__) || defined(__mips__)
#include <sys/stat.h>
#else
#define ino_t __kernel_ino_t
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_netbsd.cpp b/libsanitizer/sanitizer_common/sanitizer_platform_limits_netbsd.cpp
index f01de6c995e..25da334b63f 100644
--- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_netbsd.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_netbsd.cpp
@@ -17,6 +17,7 @@
#define _KMEMUSER
#define RAY_DO_SIGLEV
+#define __LEGACY_PT_LWPINFO
// clang-format off
#include <sys/param.h>
@@ -71,6 +72,15 @@
#include <sys/msg.h>
#include <sys/mtio.h>
#include <sys/ptrace.h>
+
+// Compat for NetBSD < 9.99.30.
+#ifndef PT_LWPSTATUS
+#define PT_LWPSTATUS 24
+#endif
+#ifndef PT_LWPNEXT
+#define PT_LWPNEXT 25
+#endif
+
#include <sys/resource.h>
#include <sys/sem.h>
#include <sys/sha1.h>
@@ -109,7 +119,12 @@
#include <dev/dmover/dmover_io.h>
#include <dev/dtv/dtvio_demux.h>
#include <dev/dtv/dtvio_frontend.h>
+#if !__NetBSD_Prereq__(9, 99, 26)
#include <dev/filemon/filemon.h>
+#else
+#define FILEMON_SET_FD _IOWR('S', 1, int)
+#define FILEMON_SET_PID _IOWR('S', 2, pid_t)
+#endif
#include <dev/hdaudio/hdaudioio.h>
#include <dev/hdmicec/hdmicecio.h>
#include <dev/hpc/hpcfbio.h>
@@ -146,12 +161,121 @@
#include <net/slip.h>
#include <netbt/hci.h>
#include <netinet/ip_compat.h>
+#if __has_include(<netinet/ip_fil.h>)
#include <netinet/ip_fil.h>
#include <netinet/ip_nat.h>
#include <netinet/ip_proxy.h>
+#else
+/* Fallback for MKIPFILTER=no */
+
+typedef struct ap_control {
+ char apc_label[16];
+ char apc_config[16];
+ unsigned char apc_p;
+ unsigned long apc_cmd;
+ unsigned long apc_arg;
+ void *apc_data;
+ size_t apc_dsize;
+} ap_ctl_t;
+
+typedef struct ipftq {
+ ipfmutex_t ifq_lock;
+ unsigned int ifq_ttl;
+ void *ifq_head;
+ void **ifq_tail;
+ void *ifq_next;
+ void **ifq_pnext;
+ int ifq_ref;
+ unsigned int ifq_flags;
+} ipftq_t;
+
+typedef struct ipfobj {
+ uint32_t ipfo_rev;
+ uint32_t ipfo_size;
+ void *ipfo_ptr;
+ int ipfo_type;
+ int ipfo_offset;
+ int ipfo_retval;
+ unsigned char ipfo_xxxpad[28];
+} ipfobj_t;
+
+#define SIOCADNAT _IOW('r', 60, struct ipfobj)
+#define SIOCRMNAT _IOW('r', 61, struct ipfobj)
+#define SIOCGNATS _IOWR('r', 62, struct ipfobj)
+#define SIOCGNATL _IOWR('r', 63, struct ipfobj)
+#define SIOCPURGENAT _IOWR('r', 100, struct ipfobj)
+#endif
#include <netinet6/in6_var.h>
#include <netinet6/nd6.h>
+#if !__NetBSD_Prereq__(9, 99, 51)
#include <netsmb/smb_dev.h>
+#else
+struct smbioc_flags {
+ int ioc_level;
+ int ioc_mask;
+ int ioc_flags;
+};
+struct smbioc_oshare {
+ int ioc_opt;
+ int ioc_stype;
+ char ioc_share[129];
+ char ioc_password[129];
+ uid_t ioc_owner;
+ gid_t ioc_group;
+ mode_t ioc_mode;
+ mode_t ioc_rights;
+};
+struct smbioc_ossn {
+ int ioc_opt;
+ uint32_t ioc_svlen;
+ struct sockaddr *ioc_server;
+ uint32_t ioc_lolen;
+ struct sockaddr *ioc_local;
+ char ioc_srvname[16];
+ int ioc_timeout;
+ int ioc_retrycount;
+ char ioc_localcs[16];
+ char ioc_servercs[16];
+ char ioc_user[129];
+ char ioc_workgroup[129];
+ char ioc_password[129];
+ uid_t ioc_owner;
+ gid_t ioc_group;
+ mode_t ioc_mode;
+ mode_t ioc_rights;
+};
+struct smbioc_lookup {
+ int ioc_level;
+ int ioc_flags;
+ struct smbioc_ossn ioc_ssn;
+ struct smbioc_oshare ioc_sh;
+};
+struct smbioc_rq {
+ u_char ioc_cmd;
+ u_char ioc_twc;
+ void *ioc_twords;
+ u_short ioc_tbc;
+ void *ioc_tbytes;
+ int ioc_rpbufsz;
+ char *ioc_rpbuf;
+ u_char ioc_rwc;
+ u_short ioc_rbc;
+};
+struct smbioc_rw {
+ u_int16_t ioc_fh;
+ char *ioc_base;
+ off_t ioc_offset;
+ int ioc_cnt;
+};
+#define SMBIOC_OPENSESSION _IOW('n', 100, struct smbioc_ossn)
+#define SMBIOC_OPENSHARE _IOW('n', 101, struct smbioc_oshare)
+#define SMBIOC_REQUEST _IOWR('n', 102, struct smbioc_rq)
+#define SMBIOC_T2RQ _IOWR('n', 103, struct smbioc_t2rq)
+#define SMBIOC_SETFLAGS _IOW('n', 104, struct smbioc_flags)
+#define SMBIOC_LOOKUP _IOW('n', 106, struct smbioc_lookup)
+#define SMBIOC_READ _IOWR('n', 107, struct smbioc_rw)
+#define SMBIOC_WRITE _IOWR('n', 108, struct smbioc_rw)
+#endif
#include <dev/biovar.h>
#include <dev/bluetooth/btdev.h>
#include <dev/bluetooth/btsco.h>
@@ -175,7 +299,21 @@
#include <dev/sun/vuid_event.h>
#include <dev/tc/sticio.h>
#include <dev/usb/ukyopon.h>
+#if !__NetBSD_Prereq__(9, 99, 44)
#include <dev/usb/urio.h>
+#else
+struct urio_command {
+ unsigned short length;
+ int request;
+ int requesttype;
+ int value;
+ int index;
+ void *buffer;
+ int timeout;
+};
+#define URIO_SEND_COMMAND _IOWR('U', 200, struct urio_command)
+#define URIO_RECV_COMMAND _IOWR('U', 201, struct urio_command)
+#endif
#include <dev/usb/usb.h>
#include <dev/usb/utoppy.h>
#include <dev/vme/xio.h>
@@ -184,6 +322,7 @@
#include <dev/wscons/wsdisplay_usl_io.h>
#include <fs/autofs/autofs_ioctl.h>
#include <dirent.h>
+#include <dlfcn.h>
#include <glob.h>
#include <grp.h>
#include <ifaddrs.h>
@@ -229,9 +368,15 @@
// Include these after system headers to avoid name clashes and ambiguities.
#include "sanitizer_internal_defs.h"
+#include "sanitizer_libc.h"
#include "sanitizer_platform_limits_netbsd.h"
namespace __sanitizer {
+void *__sanitizer_get_link_map_by_dlopen_handle(void* handle) {
+ void *p = nullptr;
+ return internal_dlinfo(handle, RTLD_DI_LINKMAP, &p) == 0 ? p : nullptr;
+}
+
unsigned struct_utsname_sz = sizeof(struct utsname);
unsigned struct_stat_sz = sizeof(struct stat);
unsigned struct_rusage_sz = sizeof(struct rusage);
@@ -240,6 +385,7 @@ unsigned struct_passwd_sz = sizeof(struct passwd);
unsigned struct_group_sz = sizeof(struct group);
unsigned siginfo_t_sz = sizeof(siginfo_t);
unsigned struct_sigaction_sz = sizeof(struct sigaction);
+unsigned struct_stack_t_sz = sizeof(stack_t);
unsigned struct_itimerval_sz = sizeof(struct itimerval);
unsigned pthread_t_sz = sizeof(pthread_t);
unsigned pthread_mutex_t_sz = sizeof(pthread_mutex_t);
@@ -287,6 +433,8 @@ int ptrace_pt_get_event_mask = PT_GET_EVENT_MASK;
int ptrace_pt_get_process_state = PT_GET_PROCESS_STATE;
int ptrace_pt_set_siginfo = PT_SET_SIGINFO;
int ptrace_pt_get_siginfo = PT_GET_SIGINFO;
+int ptrace_pt_lwpstatus = PT_LWPSTATUS;
+int ptrace_pt_lwpnext = PT_LWPNEXT;
int ptrace_piod_read_d = PIOD_READ_D;
int ptrace_piod_write_d = PIOD_WRITE_D;
int ptrace_piod_read_i = PIOD_READ_I;
@@ -319,6 +467,8 @@ int ptrace_pt_getdbregs = -1;
unsigned struct_ptrace_ptrace_io_desc_struct_sz = sizeof(struct ptrace_io_desc);
unsigned struct_ptrace_ptrace_lwpinfo_struct_sz = sizeof(struct ptrace_lwpinfo);
+unsigned struct_ptrace_ptrace_lwpstatus_struct_sz =
+ sizeof(struct __sanitizer_ptrace_lwpstatus);
unsigned struct_ptrace_ptrace_event_struct_sz = sizeof(ptrace_event_t);
unsigned struct_ptrace_ptrace_siginfo_struct_sz = sizeof(ptrace_siginfo_t);
@@ -698,6 +848,7 @@ unsigned struct_nvmm_ioc_machine_configure_sz =
sizeof(nvmm_ioc_machine_configure);
unsigned struct_nvmm_ioc_vcpu_create_sz = sizeof(nvmm_ioc_vcpu_create);
unsigned struct_nvmm_ioc_vcpu_destroy_sz = sizeof(nvmm_ioc_vcpu_destroy);
+unsigned struct_nvmm_ioc_vcpu_configure_sz = sizeof(nvmm_ioc_vcpu_configure);
unsigned struct_nvmm_ioc_vcpu_setstate_sz = sizeof(nvmm_ioc_vcpu_destroy);
unsigned struct_nvmm_ioc_vcpu_getstate_sz = sizeof(nvmm_ioc_vcpu_getstate);
unsigned struct_nvmm_ioc_vcpu_inject_sz = sizeof(nvmm_ioc_vcpu_inject);
@@ -1458,6 +1609,7 @@ unsigned IOCTL_NVMM_IOC_MACHINE_DESTROY = NVMM_IOC_MACHINE_DESTROY;
unsigned IOCTL_NVMM_IOC_MACHINE_CONFIGURE = NVMM_IOC_MACHINE_CONFIGURE;
unsigned IOCTL_NVMM_IOC_VCPU_CREATE = NVMM_IOC_VCPU_CREATE;
unsigned IOCTL_NVMM_IOC_VCPU_DESTROY = NVMM_IOC_VCPU_DESTROY;
+unsigned IOCTL_NVMM_IOC_VCPU_CONFIGURE = NVMM_IOC_VCPU_CONFIGURE;
unsigned IOCTL_NVMM_IOC_VCPU_SETSTATE = NVMM_IOC_VCPU_SETSTATE;
unsigned IOCTL_NVMM_IOC_VCPU_GETSTATE = NVMM_IOC_VCPU_GETSTATE;
unsigned IOCTL_NVMM_IOC_VCPU_INJECT = NVMM_IOC_VCPU_INJECT;
@@ -1534,6 +1686,7 @@ unsigned IOCTL_IOC_NPF_STATS = IOC_NPF_STATS;
unsigned IOCTL_IOC_NPF_SAVE = IOC_NPF_SAVE;
unsigned IOCTL_IOC_NPF_RULE = IOC_NPF_RULE;
unsigned IOCTL_IOC_NPF_CONN_LOOKUP = IOC_NPF_CONN_LOOKUP;
+unsigned IOCTL_IOC_NPF_TABLE_REPLACE = IOC_NPF_TABLE_REPLACE;
unsigned IOCTL_PPPOESETPARMS = PPPOESETPARMS;
unsigned IOCTL_PPPOEGETPARMS = PPPOEGETPARMS;
unsigned IOCTL_PPPOEGETSESSION = PPPOEGETSESSION;
@@ -2392,4 +2545,42 @@ CHECK_SIZE_AND_OFFSET(modctl_load_t, ml_flags);
CHECK_SIZE_AND_OFFSET(modctl_load_t, ml_props);
CHECK_SIZE_AND_OFFSET(modctl_load_t, ml_propslen);
+// Compat with 9.0
+struct statvfs90 {
+ unsigned long f_flag;
+ unsigned long f_bsize;
+ unsigned long f_frsize;
+ unsigned long f_iosize;
+
+ u64 f_blocks;
+ u64 f_bfree;
+ u64 f_bavail;
+ u64 f_bresvd;
+
+ u64 f_files;
+ u64 f_ffree;
+ u64 f_favail;
+ u64 f_fresvd;
+
+ u64 f_syncreads;
+ u64 f_syncwrites;
+
+ u64 f_asyncreads;
+ u64 f_asyncwrites;
+
+ struct {
+ s32 __fsid_val[2];
+ } f_fsidx;
+ unsigned long f_fsid;
+ unsigned long f_namemax;
+ u32 f_owner;
+
+ u32 f_spare[4];
+
+ char f_fstypename[32];
+ char f_mntonname[32];
+ char f_mntfromname[32];
+};
+unsigned struct_statvfs90_sz = sizeof(struct statvfs90);
+
#endif // SANITIZER_NETBSD
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_netbsd.h b/libsanitizer/sanitizer_common/sanitizer_platform_limits_netbsd.h
index 419d830c69e..d80280d9bf8 100644
--- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_netbsd.h
+++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_netbsd.h
@@ -19,18 +19,11 @@
#include "sanitizer_internal_defs.h"
#include "sanitizer_platform.h"
-#define _GET_LINK_MAP_BY_DLOPEN_HANDLE(handle, shift) \
- ((link_map *)((handle) == nullptr ? nullptr : ((char *)(handle) + (shift))))
-
-#if defined(__x86_64__)
-#define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \
- _GET_LINK_MAP_BY_DLOPEN_HANDLE(handle, 264)
-#elif defined(__i386__)
-#define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \
- _GET_LINK_MAP_BY_DLOPEN_HANDLE(handle, 136)
-#endif
-
namespace __sanitizer {
+void *__sanitizer_get_link_map_by_dlopen_handle(void *handle);
+# define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \
+ (link_map *)__sanitizer_get_link_map_by_dlopen_handle(handle)
+
extern unsigned struct_utsname_sz;
extern unsigned struct_stat_sz;
extern unsigned struct_rusage_sz;
@@ -48,6 +41,7 @@ extern unsigned struct_timezone_sz;
extern unsigned struct_tms_sz;
extern unsigned struct_itimerspec_sz;
extern unsigned struct_sigevent_sz;
+extern unsigned struct_stack_t_sz;
extern unsigned struct_sched_param_sz;
extern unsigned struct_statfs_sz;
extern unsigned struct_sockaddr_sz;
@@ -412,6 +406,8 @@ extern int ptrace_pt_get_event_mask;
extern int ptrace_pt_get_process_state;
extern int ptrace_pt_set_siginfo;
extern int ptrace_pt_get_siginfo;
+extern int ptrace_pt_lwpstatus;
+extern int ptrace_pt_lwpnext;
extern int ptrace_piod_read_d;
extern int ptrace_piod_write_d;
extern int ptrace_piod_read_i;
@@ -436,8 +432,17 @@ struct __sanitizer_ptrace_lwpinfo {
int pl_event;
};
+struct __sanitizer_ptrace_lwpstatus {
+ __sanitizer_lwpid_t pl_lwpid;
+ __sanitizer_sigset_t pl_sigpend;
+ __sanitizer_sigset_t pl_sigmask;
+ char pl_name[20];
+ void *pl_private;
+};
+
extern unsigned struct_ptrace_ptrace_io_desc_struct_sz;
extern unsigned struct_ptrace_ptrace_lwpinfo_struct_sz;
+extern unsigned struct_ptrace_ptrace_lwpstatus_struct_sz;
extern unsigned struct_ptrace_ptrace_event_struct_sz;
extern unsigned struct_ptrace_ptrace_siginfo_struct_sz;
@@ -862,6 +867,7 @@ extern unsigned struct_nvmm_ioc_machine_destroy_sz;
extern unsigned struct_nvmm_ioc_machine_configure_sz;
extern unsigned struct_nvmm_ioc_vcpu_create_sz;
extern unsigned struct_nvmm_ioc_vcpu_destroy_sz;
+extern unsigned struct_nvmm_ioc_vcpu_configure_sz;
extern unsigned struct_nvmm_ioc_vcpu_setstate_sz;
extern unsigned struct_nvmm_ioc_vcpu_getstate_sz;
extern unsigned struct_nvmm_ioc_vcpu_inject_sz;
@@ -1611,6 +1617,7 @@ extern unsigned IOCTL_NVMM_IOC_MACHINE_DESTROY;
extern unsigned IOCTL_NVMM_IOC_MACHINE_CONFIGURE;
extern unsigned IOCTL_NVMM_IOC_VCPU_CREATE;
extern unsigned IOCTL_NVMM_IOC_VCPU_DESTROY;
+extern unsigned IOCTL_NVMM_IOC_VCPU_CONFIGURE;
extern unsigned IOCTL_NVMM_IOC_VCPU_SETSTATE;
extern unsigned IOCTL_NVMM_IOC_VCPU_GETSTATE;
extern unsigned IOCTL_NVMM_IOC_VCPU_INJECT;
@@ -1685,6 +1692,7 @@ extern unsigned IOCTL_IOC_NPF_STATS;
extern unsigned IOCTL_IOC_NPF_SAVE;
extern unsigned IOCTL_IOC_NPF_RULE;
extern unsigned IOCTL_IOC_NPF_CONN_LOOKUP;
+extern unsigned IOCTL_IOC_NPF_TABLE_REPLACE;
extern unsigned IOCTL_PPPOESETPARMS;
extern unsigned IOCTL_PPPOEGETPARMS;
extern unsigned IOCTL_PPPOEGETSESSION;
@@ -2406,6 +2414,9 @@ struct __sanitizer_cdbw {
#define SIGACTION_SYMNAME __sigaction14
+// Compat with 9.0
+extern unsigned struct_statvfs90_sz;
+
#endif // SANITIZER_NETBSD
#endif
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_openbsd.cpp b/libsanitizer/sanitizer_common/sanitizer_platform_limits_openbsd.cpp
index 12515626ce5..1420ecbfa56 100644
--- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_openbsd.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_openbsd.cpp
@@ -72,6 +72,7 @@ unsigned struct_passwd_sz = sizeof(struct passwd);
unsigned struct_group_sz = sizeof(struct group);
unsigned siginfo_t_sz = sizeof(siginfo_t);
unsigned struct_sigaction_sz = sizeof(struct sigaction);
+unsigned struct_stack_t_sz = sizeof(stack_t);
unsigned struct_itimerval_sz = sizeof(struct itimerval);
unsigned pthread_t_sz = sizeof(pthread_t);
unsigned pthread_mutex_t_sz = sizeof(pthread_mutex_t);
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_openbsd.h b/libsanitizer/sanitizer_common/sanitizer_platform_limits_openbsd.h
index 6d8b062716b..8a194872360 100644
--- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_openbsd.h
+++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_openbsd.h
@@ -50,6 +50,7 @@ extern unsigned struct_timezone_sz;
extern unsigned struct_tms_sz;
extern unsigned struct_itimerspec_sz;
extern unsigned struct_sigevent_sz;
+extern unsigned struct_stack_t_sz;
extern unsigned struct_statfs_sz;
extern unsigned struct_sockaddr_sz;
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp
index aa845df4dde..e71515f12e9 100644
--- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp
@@ -179,6 +179,7 @@ namespace __sanitizer {
unsigned struct_group_sz = sizeof(struct group);
unsigned siginfo_t_sz = sizeof(siginfo_t);
unsigned struct_sigaction_sz = sizeof(struct sigaction);
+ unsigned struct_stack_t_sz = sizeof(stack_t);
unsigned struct_itimerval_sz = sizeof(struct itimerval);
unsigned pthread_t_sz = sizeof(pthread_t);
unsigned pthread_mutex_t_sz = sizeof(pthread_mutex_t);
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h
index d82fd5e4005..f6c8a1450a9 100644
--- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h
+++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h
@@ -47,6 +47,7 @@ extern unsigned struct_timezone_sz;
extern unsigned struct_tms_sz;
extern unsigned struct_itimerspec_sz;
extern unsigned struct_sigevent_sz;
+extern unsigned struct_stack_t_sz;
extern unsigned struct_sched_param_sz;
extern unsigned struct_statfs64_sz;
extern unsigned struct_regex_sz;
@@ -82,7 +83,7 @@ const unsigned struct_kernel_stat64_sz = 104;
#elif defined(__mips__)
const unsigned struct_kernel_stat_sz = SANITIZER_ANDROID
? FIRST_32_SECOND_64(104, 128)
- : FIRST_32_SECOND_64(144, 216);
+ : FIRST_32_SECOND_64(160, 216);
const unsigned struct_kernel_stat64_sz = 104;
#elif defined(__s390__) && !defined(__s390x__)
const unsigned struct_kernel_stat_sz = 64;
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_solaris.cpp b/libsanitizer/sanitizer_common/sanitizer_platform_limits_solaris.cpp
index 9717d98ebf1..6ec1a1bdd11 100644
--- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_solaris.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_solaris.cpp
@@ -72,6 +72,7 @@ namespace __sanitizer {
unsigned struct_group_sz = sizeof(struct group);
unsigned siginfo_t_sz = sizeof(siginfo_t);
unsigned struct_sigaction_sz = sizeof(struct sigaction);
+ unsigned struct_stack_t_sz = sizeof(stack_t);
unsigned struct_itimerval_sz = sizeof(struct itimerval);
unsigned pthread_t_sz = sizeof(pthread_t);
unsigned pthread_mutex_t_sz = sizeof(pthread_mutex_t);
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_solaris.h b/libsanitizer/sanitizer_common/sanitizer_platform_limits_solaris.h
index 77ae6e6a44d..85995e79792 100644
--- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_solaris.h
+++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_solaris.h
@@ -38,6 +38,7 @@ extern unsigned struct_timezone_sz;
extern unsigned struct_tms_sz;
extern unsigned struct_itimerspec_sz;
extern unsigned struct_sigevent_sz;
+extern unsigned struct_stack_t_sz;
extern unsigned struct_sched_param_sz;
extern unsigned struct_statfs64_sz;
extern unsigned struct_statfs_sz;
diff --git a/libsanitizer/sanitizer_common/sanitizer_posix.cpp b/libsanitizer/sanitizer_common/sanitizer_posix.cpp
index d890a3a3177..e21661b42f8 100644
--- a/libsanitizer/sanitizer_common/sanitizer_posix.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_posix.cpp
@@ -347,9 +347,17 @@ int GetNamedMappingFd(const char *name, uptr size, int *flags) {
CHECK(internal_strlen(name) < sizeof(shmname) - 10);
internal_snprintf(shmname, sizeof(shmname), "/dev/shm/%zu [%s]",
internal_getpid(), name);
+ int o_cloexec = 0;
+#if defined(O_CLOEXEC)
+ o_cloexec = O_CLOEXEC;
+#endif
int fd = ReserveStandardFds(
- internal_open(shmname, O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, S_IRWXU));
+ internal_open(shmname, O_RDWR | O_CREAT | O_TRUNC | o_cloexec, S_IRWXU));
CHECK_GE(fd, 0);
+ if (!o_cloexec) {
+ int res = fcntl(fd, F_SETFD, FD_CLOEXEC);
+ CHECK_EQ(0, res);
+ }
int res = internal_ftruncate(fd, size);
CHECK_EQ(0, res);
res = internal_unlink(shmname);
diff --git a/libsanitizer/sanitizer_common/sanitizer_posix.h b/libsanitizer/sanitizer_common/sanitizer_posix.h
index 05fb0f63020..a1b49702da2 100644
--- a/libsanitizer/sanitizer_common/sanitizer_posix.h
+++ b/libsanitizer/sanitizer_common/sanitizer_posix.h
@@ -39,7 +39,7 @@ uptr internal_write(fd_t fd, const void *buf, uptr count);
// Memory
uptr internal_mmap(void *addr, uptr length, int prot, int flags,
- int fd, OFF_T offset);
+ int fd, u64 offset);
uptr internal_munmap(void *addr, uptr length);
int internal_mprotect(void *addr, uptr length, int prot);
@@ -63,7 +63,7 @@ uptr internal_ptrace(int request, int pid, void *addr, void *data);
uptr internal_waitpid(int pid, int *status, int options);
int internal_fork();
-fd_t internal_spawn(const char *argv[], pid_t *pid);
+fd_t internal_spawn(const char *argv[], const char *envp[], pid_t *pid);
int internal_sysctl(const int *name, unsigned int namelen, void *oldp,
uptr *oldlenp, const void *newp, uptr newlen);
diff --git a/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp
index 304b3a01a08..f920172c06d 100644
--- a/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp
@@ -426,7 +426,8 @@ void AdjustStackSize(void *attr_) {
#endif // !SANITIZER_GO
pid_t StartSubprocess(const char *program, const char *const argv[],
- fd_t stdin_fd, fd_t stdout_fd, fd_t stderr_fd) {
+ const char *const envp[], fd_t stdin_fd, fd_t stdout_fd,
+ fd_t stderr_fd) {
auto file_closer = at_scope_exit([&] {
if (stdin_fd != kInvalidFd) {
internal_close(stdin_fd);
@@ -469,7 +470,8 @@ pid_t StartSubprocess(const char *program, const char *const argv[],
for (int fd = sysconf(_SC_OPEN_MAX); fd > 2; fd--) internal_close(fd);
- execv(program, const_cast<char **>(&argv[0]));
+ internal_execve(program, const_cast<char **>(&argv[0]),
+ const_cast<char *const *>(envp));
internal__exit(1);
}
diff --git a/libsanitizer/sanitizer_common/sanitizer_procmaps.h b/libsanitizer/sanitizer_common/sanitizer_procmaps.h
index d0e5245f84d..665ed45fa93 100644
--- a/libsanitizer/sanitizer_common/sanitizer_procmaps.h
+++ b/libsanitizer/sanitizer_common/sanitizer_procmaps.h
@@ -15,18 +15,19 @@
#include "sanitizer_platform.h"
-#if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || \
- SANITIZER_OPENBSD || SANITIZER_MAC || SANITIZER_SOLARIS
+#if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || \
+ SANITIZER_OPENBSD || SANITIZER_MAC || SANITIZER_SOLARIS || \
+ SANITIZER_FUCHSIA
#include "sanitizer_common.h"
#include "sanitizer_internal_defs.h"
+#include "sanitizer_fuchsia.h"
#include "sanitizer_linux.h"
#include "sanitizer_mac.h"
#include "sanitizer_mutex.h"
namespace __sanitizer {
-
// Memory protection masks.
static const uptr kProtectionRead = 1;
static const uptr kProtectionWrite = 2;
diff --git a/libsanitizer/sanitizer_common/sanitizer_procmaps_fuchsia.cpp b/libsanitizer/sanitizer_common/sanitizer_procmaps_fuchsia.cpp
new file mode 100644
index 00000000000..cc3e9be0645
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_procmaps_fuchsia.cpp
@@ -0,0 +1,80 @@
+//===-- sanitizer_procmaps_fuchsia.cpp
+//----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Information about the process mappings (Fuchsia-specific parts).
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+#if SANITIZER_FUCHSIA
+#include <zircon/process.h>
+#include <zircon/syscalls.h>
+
+#include "sanitizer_common.h"
+#include "sanitizer_procmaps.h"
+
+namespace __sanitizer {
+
+// The cache flag is ignored on Fuchsia because a process can always get this
+// information via its process-self handle.
+MemoryMappingLayout::MemoryMappingLayout(bool) { Reset(); }
+
+void MemoryMappingLayout::Reset() {
+ data_.data.clear();
+ data_.current = 0;
+
+ size_t count;
+ zx_status_t status = _zx_object_get_info(
+ _zx_process_self(), ZX_INFO_PROCESS_MAPS, nullptr, 0, nullptr, &count);
+ if (status != ZX_OK) {
+ return;
+ }
+
+ size_t filled;
+ do {
+ data_.data.resize(count);
+ status = _zx_object_get_info(
+ _zx_process_self(), ZX_INFO_PROCESS_MAPS, data_.data.data(),
+ count * sizeof(zx_info_maps_t), &filled, &count);
+ if (status != ZX_OK) {
+ data_.data.clear();
+ return;
+ }
+ } while (filled < count);
+}
+
+MemoryMappingLayout::~MemoryMappingLayout() {}
+
+bool MemoryMappingLayout::Error() const { return data_.data.empty(); }
+
+bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) {
+ while (data_.current < data_.data.size()) {
+ const auto &entry = data_.data[data_.current++];
+ if (entry.type == ZX_INFO_MAPS_TYPE_MAPPING) {
+ segment->start = entry.base;
+ segment->end = entry.base + entry.size;
+ segment->offset = entry.u.mapping.vmo_offset;
+ const auto flags = entry.u.mapping.mmu_flags;
+ segment->protection =
+ ((flags & ZX_VM_PERM_READ) ? kProtectionRead : 0) |
+ ((flags & ZX_VM_PERM_WRITE) ? kProtectionWrite : 0) |
+ ((flags & ZX_VM_PERM_EXECUTE) ? kProtectionExecute : 0);
+ if (segment->filename && segment->filename_size > 0) {
+ uptr len = Min(sizeof(entry.name), segment->filename_size) - 1;
+ internal_strncpy(segment->filename, entry.name, len);
+ segment->filename[len] = 0;
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_FUCHSIA
diff --git a/libsanitizer/sanitizer_common/sanitizer_ptrauth.h b/libsanitizer/sanitizer_common/sanitizer_ptrauth.h
new file mode 100644
index 00000000000..4d0d96a64f6
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_ptrauth.h
@@ -0,0 +1,21 @@
+//===-- sanitizer_ptrauth.h -------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_PTRAUTH_H
+#define SANITIZER_PTRAUTH_H
+
+#if __has_feature(ptrauth_calls)
+#include <ptrauth.h>
+#else
+// Copied from <ptrauth.h>
+#define ptrauth_strip(__value, __key) __value
+#define ptrauth_auth_data(__value, __old_key, __old_data) __value
+#define ptrauth_string_discriminator(__string) ((int)0)
+#endif
+
+#endif // SANITIZER_PTRAUTH_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_rtems.cpp b/libsanitizer/sanitizer_common/sanitizer_rtems.cpp
index 0d2576c00ab..29bcfcfa6f1 100644
--- a/libsanitizer/sanitizer_common/sanitizer_rtems.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_rtems.cpp
@@ -49,6 +49,10 @@ uptr internal_getpid() {
return getpid();
}
+int internal_dlinfo(void *handle, int request, void *p) {
+ UNIMPLEMENTED();
+}
+
bool FileExists(const char *filename) {
struct stat st;
if (stat(filename, &st))
diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp b/libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp
index ce75cbe5d26..ef14fb704ee 100644
--- a/libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp
@@ -60,8 +60,8 @@ static inline uhwptr *GetCanonicFrame(uptr bp,
// Nope, this does not look right either. This means the frame after next does
// not have a valid frame pointer, but we can still extract the caller PC.
// Unfortunately, there is no way to decide between GCC and LLVM frame
- // layouts. Assume GCC.
- return bp_prev - 1;
+ // layouts. Assume LLVM.
+ return bp_prev;
#else
return (uhwptr*)bp;
#endif
@@ -84,21 +84,14 @@ void BufferedStackTrace::UnwindFast(uptr pc, uptr bp, uptr stack_top,
IsAligned((uptr)frame, sizeof(*frame)) &&
size < max_depth) {
#ifdef __powerpc__
- // PowerPC ABIs specify that the return address is saved on the
- // *caller's* stack frame. Thus we must dereference the back chain
- // to find the caller frame before extracting it.
+ // PowerPC ABIs specify that the return address is saved at offset
+ // 16 of the *caller's* stack frame. Thus we must dereference the
+ // back chain to find the caller frame before extracting it.
uhwptr *caller_frame = (uhwptr*)frame[0];
if (!IsValidFrame((uptr)caller_frame, stack_top, bottom) ||
!IsAligned((uptr)caller_frame, sizeof(uhwptr)))
break;
- // For most ABIs the offset where the return address is saved is two
- // register sizes. The exception is the SVR4 ABI, which uses an
- // offset of only one register size.
-#ifdef _CALL_SYSV
- uhwptr pc1 = caller_frame[1];
-#else
uhwptr pc1 = caller_frame[2];
-#endif
#elif defined(__s390__)
uhwptr pc1 = frame[14];
#else
diff --git a/libsanitizer/sanitizer_common/sanitizer_stoptheworld_fuchsia.cpp b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_fuchsia.cpp
new file mode 100644
index 00000000000..3a246443ed9
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_fuchsia.cpp
@@ -0,0 +1,42 @@
+//===-- sanitizer_stoptheworld_fuchsia.cpp -------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===---------------------------------------------------------------------===//
+//
+// See sanitizer_stoptheworld.h for details.
+//
+//===---------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+
+#if SANITIZER_FUCHSIA
+
+#include <zircon/sanitizer.h>
+
+#include "sanitizer_stoptheworld.h"
+
+namespace __sanitizer {
+
+// The Fuchsia implementation stops the world but doesn't offer a real
+// SuspendedThreadsList argument. This is enough for ASan's use case,
+// and LSan does not use this API on Fuchsia.
+void StopTheWorld(StopTheWorldCallback callback, void *argument) {
+ struct Params {
+ StopTheWorldCallback callback;
+ void *argument;
+ } params = {callback, argument};
+ __sanitizer_memory_snapshot(
+ nullptr, nullptr, nullptr, nullptr,
+ [](zx_status_t, void *data) {
+ auto params = reinterpret_cast<Params *>(data);
+ params->callback({}, params->argument);
+ },
+ ¶ms);
+}
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_FUCHSIA
diff --git a/libsanitizer/sanitizer_common/sanitizer_stoptheworld_mac.cpp b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_mac.cpp
index 9dffd21ecb7..6c577426ad5 100644
--- a/libsanitizer/sanitizer_common/sanitizer_stoptheworld_mac.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_mac.cpp
@@ -50,7 +50,7 @@ struct RunThreadArgs {
void *argument;
};
-void RunThread(void *arg) {
+void *RunThread(void *arg) {
struct RunThreadArgs *run_args = (struct RunThreadArgs *)arg;
SuspendedThreadsListMac suspended_threads_list;
@@ -59,7 +59,7 @@ void RunThread(void *arg) {
kern_return_t err = task_threads(mach_task_self(), &threads, &num_threads);
if (err != KERN_SUCCESS) {
VReport(1, "Failed to get threads for task (errno %d).\n", err);
- return;
+ return nullptr;
}
thread_t thread_self = mach_thread_self();
@@ -76,6 +76,7 @@ void RunThread(void *arg) {
for (unsigned int i = 0; i < num_suspended; ++i) {
thread_resume(suspended_threads_list.GetThread(i));
}
+ return nullptr;
}
void StopTheWorld(StopTheWorldCallback callback, void *argument) {
@@ -159,7 +160,11 @@ PtraceRegistersStatus SuspendedThreadsListMac::GetRegistersAndSP(
}
internal_memcpy(buffer, ®s, sizeof(regs));
+#if defined(__aarch64__) && defined(arm_thread_state64_get_sp)
+ *sp = arm_thread_state64_get_sp(regs);
+#else
*sp = regs.SP_REG;
+#endif
// On x86_64 and aarch64, we must account for the stack redzone, which is 128
// bytes.
diff --git a/libsanitizer/sanitizer_common/sanitizer_stoptheworld_netbsd_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_netbsd_libcdep.cpp
index 5690d75097f..1ed21343254 100644
--- a/libsanitizer/sanitizer_common/sanitizer_stoptheworld_netbsd_libcdep.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_netbsd_libcdep.cpp
@@ -120,10 +120,18 @@ bool ThreadSuspender::SuspendAllThreads() {
VReport(2, "Attached to process %d.\n", pid_);
+#ifdef PT_LWPNEXT
+ struct ptrace_lwpstatus pl;
+ int op = PT_LWPNEXT;
+#else
struct ptrace_lwpinfo pl;
- int val;
+ int op = PT_LWPINFO;
+#endif
+
pl.pl_lwpid = 0;
- while ((val = ptrace(PT_LWPINFO, pid_, (void *)&pl, sizeof(pl))) != -1 &&
+
+ int val;
+ while ((val = ptrace(op, pid_, (void *)&pl, sizeof(pl))) != -1 &&
pl.pl_lwpid != 0) {
suspended_threads_list_.Append(pl.pl_lwpid);
VReport(2, "Appended thread %d in process %d.\n", pl.pl_lwpid, pid_);
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer.cpp
index ce2ece5f4d5..0c4b84c767a 100644
--- a/libsanitizer/sanitizer_common/sanitizer_symbolizer.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer.cpp
@@ -126,4 +126,10 @@ Symbolizer::SymbolizerScope::~SymbolizerScope() {
sym_->end_hook_();
}
+void Symbolizer::LateInitializeTools() {
+ for (auto &tool : tools_) {
+ tool.LateInitialize();
+ }
+}
+
} // namespace __sanitizer
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer.h b/libsanitizer/sanitizer_common/sanitizer_symbolizer.h
index 51648e2d0e8..2476b0ea7bf 100644
--- a/libsanitizer/sanitizer_common/sanitizer_symbolizer.h
+++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer.h
@@ -209,6 +209,9 @@ class Symbolizer final {
private:
const Symbolizer *sym_;
};
+
+ // Calls `LateInitialize()` on all items in `tools_`.
+ void LateInitializeTools();
};
#ifdef SANITIZER_WINDOWS
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_internal.h b/libsanitizer/sanitizer_common/sanitizer_symbolizer_internal.h
index c04797dd61b..e4c351e667b 100644
--- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_internal.h
+++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_internal.h
@@ -69,6 +69,11 @@ class SymbolizerTool {
virtual const char *Demangle(const char *name) {
return nullptr;
}
+
+ // Called during the LateInitialize phase of Sanitizer initialization.
+ // Usually this is a safe place to call code that might need to use user
+ // memory allocators.
+ virtual void LateInitialize() {}
};
// SymbolizerProcess encapsulates communication between the tool and
@@ -86,6 +91,8 @@ class SymbolizerProcess {
// Customizable by subclasses.
virtual bool StartSymbolizerSubprocess();
virtual bool ReadFromSymbolizer(char *buffer, uptr max_length);
+ // Return the environment to run the symbolizer in.
+ virtual char **GetEnvP() { return GetEnviron(); }
private:
virtual bool ReachedEndOfOutput(const char *buffer, uptr length) const {
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cpp
index 3b19a6836ec..490c6fe89be 100644
--- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cpp
@@ -39,9 +39,9 @@ const char *ExtractToken(const char *str, const char *delims, char **result) {
}
const char *ExtractInt(const char *str, const char *delims, int *result) {
- char *buff;
+ char *buff = nullptr;
const char *ret = ExtractToken(str, delims, &buff);
- if (buff != 0) {
+ if (buff) {
*result = (int)internal_atoll(buff);
}
InternalFree(buff);
@@ -49,9 +49,9 @@ const char *ExtractInt(const char *str, const char *delims, int *result) {
}
const char *ExtractUptr(const char *str, const char *delims, uptr *result) {
- char *buff;
+ char *buff = nullptr;
const char *ret = ExtractToken(str, delims, &buff);
- if (buff != 0) {
+ if (buff) {
*result = (uptr)internal_atoll(buff);
}
InternalFree(buff);
@@ -59,9 +59,9 @@ const char *ExtractUptr(const char *str, const char *delims, uptr *result) {
}
const char *ExtractSptr(const char *str, const char *delims, sptr *result) {
- char *buff;
+ char *buff = nullptr;
const char *ret = ExtractToken(str, delims, &buff);
- if (buff != 0) {
+ if (buff) {
*result = (sptr)internal_atoll(buff);
}
InternalFree(buff);
@@ -83,7 +83,7 @@ const char *ExtractTokenUpToDelimiter(const char *str, const char *delimiter,
SymbolizedStack *Symbolizer::SymbolizePC(uptr addr) {
BlockingMutexLock l(&mu_);
- const char *module_name;
+ const char *module_name = nullptr;
uptr module_offset;
ModuleArch arch;
SymbolizedStack *res = SymbolizedStack::New(addr);
@@ -103,7 +103,7 @@ SymbolizedStack *Symbolizer::SymbolizePC(uptr addr) {
bool Symbolizer::SymbolizeData(uptr addr, DataInfo *info) {
BlockingMutexLock l(&mu_);
- const char *module_name;
+ const char *module_name = nullptr;
uptr module_offset;
ModuleArch arch;
if (!FindModuleNameAndOffsetForAddress(addr, &module_name, &module_offset,
@@ -124,7 +124,7 @@ bool Symbolizer::SymbolizeData(uptr addr, DataInfo *info) {
bool Symbolizer::SymbolizeFrame(uptr addr, FrameInfo *info) {
BlockingMutexLock l(&mu_);
- const char *module_name;
+ const char *module_name = nullptr;
if (!FindModuleNameAndOffsetForAddress(
addr, &module_name, &info->module_offset, &info->module_arch))
return false;
@@ -175,7 +175,7 @@ bool Symbolizer::FindModuleNameAndOffsetForAddress(uptr address,
uptr *module_offset,
ModuleArch *module_arch) {
const LoadedModule *module = FindModuleForAddress(address);
- if (module == nullptr)
+ if (!module)
return false;
*module_name = module->full_name();
*module_offset = address - module->base_address();
@@ -292,7 +292,7 @@ LLVMSymbolizer::LLVMSymbolizer(const char *path, LowLevelAllocator *allocator)
// Windows, so extract tokens from the right hand side first. The column info is
// also optional.
static const char *ParseFileLineInfo(AddressInfo *info, const char *str) {
- char *file_line_info = 0;
+ char *file_line_info = nullptr;
str = ExtractToken(str, "\n", &file_line_info);
CHECK(file_line_info);
@@ -323,7 +323,7 @@ void ParseSymbolizePCOutput(const char *str, SymbolizedStack *res) {
bool top_frame = true;
SymbolizedStack *last = res;
while (true) {
- char *function_name = 0;
+ char *function_name = nullptr;
str = ExtractToken(str, "\n", &function_name);
CHECK(function_name);
if (function_name[0] == '\0') {
@@ -402,32 +402,29 @@ bool LLVMSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) {
AddressInfo *info = &stack->info;
const char *buf = FormatAndSendCommand(
"CODE", info->module, info->module_offset, info->module_arch);
- if (buf) {
- ParseSymbolizePCOutput(buf, stack);
- return true;
- }
- return false;
+ if (!buf)
+ return false;
+ ParseSymbolizePCOutput(buf, stack);
+ return true;
}
bool LLVMSymbolizer::SymbolizeData(uptr addr, DataInfo *info) {
const char *buf = FormatAndSendCommand(
"DATA", info->module, info->module_offset, info->module_arch);
- if (buf) {
- ParseSymbolizeDataOutput(buf, info);
- info->start += (addr - info->module_offset); // Add the base address.
- return true;
- }
- return false;
+ if (!buf)
+ return false;
+ ParseSymbolizeDataOutput(buf, info);
+ info->start += (addr - info->module_offset); // Add the base address.
+ return true;
}
bool LLVMSymbolizer::SymbolizeFrame(uptr addr, FrameInfo *info) {
const char *buf = FormatAndSendCommand(
"FRAME", info->module, info->module_offset, info->module_arch);
- if (buf) {
- ParseSymbolizeFrameOutput(buf, &info->locals);
- return true;
- }
- return false;
+ if (!buf)
+ return false;
+ ParseSymbolizeFrameOutput(buf, &info->locals);
+ return true;
}
const char *LLVMSymbolizer::FormatAndSendCommand(const char *command_prefix,
@@ -435,21 +432,21 @@ const char *LLVMSymbolizer::FormatAndSendCommand(const char *command_prefix,
uptr module_offset,
ModuleArch arch) {
CHECK(module_name);
- if (arch == kModuleArchUnknown) {
- if (internal_snprintf(buffer_, kBufferSize, "%s \"%s\" 0x%zx\n",
- command_prefix, module_name,
- module_offset) >= static_cast<int>(kBufferSize)) {
- Report("WARNING: Command buffer too small");
- return nullptr;
- }
- } else {
- if (internal_snprintf(buffer_, kBufferSize, "%s \"%s:%s\" 0x%zx\n",
- command_prefix, module_name, ModuleArchToString(arch),
- module_offset) >= static_cast<int>(kBufferSize)) {
- Report("WARNING: Command buffer too small");
- return nullptr;
- }
+ int size_needed = 0;
+ if (arch == kModuleArchUnknown)
+ size_needed = internal_snprintf(buffer_, kBufferSize, "%s \"%s\" 0x%zx\n",
+ command_prefix, module_name, module_offset);
+ else
+ size_needed = internal_snprintf(buffer_, kBufferSize,
+ "%s \"%s:%s\" 0x%zx\n", command_prefix,
+ module_name, ModuleArchToString(arch),
+ module_offset);
+
+ if (size_needed >= static_cast<int>(kBufferSize)) {
+ Report("WARNING: Command buffer too small");
+ return nullptr;
}
+
return symbolizer_process_->SendCommand(buffer_);
}
@@ -492,16 +489,16 @@ const char *SymbolizerProcess::SendCommand(const char *command) {
Report("WARNING: Failed to use and restart external symbolizer!\n");
failed_to_start_ = true;
}
- return 0;
+ return nullptr;
}
const char *SymbolizerProcess::SendCommandImpl(const char *command) {
if (input_fd_ == kInvalidFd || output_fd_ == kInvalidFd)
- return 0;
+ return nullptr;
if (!WriteToSymbolizer(command, internal_strlen(command)))
- return 0;
+ return nullptr;
if (!ReadFromSymbolizer(buffer_, kBufferSize))
- return 0;
+ return nullptr;
return buffer_;
}
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.cpp
index a619ed092f0..cc233408d0c 100644
--- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.cpp
@@ -20,6 +20,7 @@
#include <dlfcn.h>
#include <errno.h>
+#include <mach/mach.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
@@ -31,6 +32,9 @@ bool DlAddrSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) {
Dl_info info;
int result = dladdr((const void *)addr, &info);
if (!result) return false;
+
+ CHECK(addr >= reinterpret_cast<uptr>(info.dli_saddr));
+ stack->info.function_offset = addr - reinterpret_cast<uptr>(info.dli_saddr);
const char *demangled = DemangleSwiftAndCXX(info.dli_sname);
if (!demangled) return false;
stack->info.function = internal_strdup(demangled);
@@ -47,18 +51,65 @@ bool DlAddrSymbolizer::SymbolizeData(uptr addr, DataInfo *datainfo) {
return true;
}
+#define K_ATOS_ENV_VAR "__check_mach_ports_lookup"
+
+// This cannot live in `AtosSymbolizerProcess` because instances of that object
+// are allocated by the internal allocator which under ASan is poisoned with
+// kAsanInternalHeapMagic.
+static char kAtosMachPortEnvEntry[] = K_ATOS_ENV_VAR "=000000000000000";
+
class AtosSymbolizerProcess : public SymbolizerProcess {
public:
- explicit AtosSymbolizerProcess(const char *path, pid_t parent_pid)
+ explicit AtosSymbolizerProcess(const char *path)
: SymbolizerProcess(path, /*use_posix_spawn*/ true) {
- // Put the string command line argument in the object so that it outlives
- // the call to GetArgV.
- internal_snprintf(pid_str_, sizeof(pid_str_), "%d", parent_pid);
+ pid_str_[0] = '\0';
+ }
+
+ void LateInitialize() {
+ if (SANITIZER_IOSSIM) {
+ // `putenv()` may call malloc/realloc so it is only safe to do this
+ // during LateInitialize() or later (i.e. we can't do this in the
+ // constructor). We also can't do this in `StartSymbolizerSubprocess()`
+ // because in TSan we switch allocators when we're symbolizing.
+ // We use `putenv()` rather than `setenv()` so that we can later directly
+ // write into the storage without LibC getting involved to change what the
+ // variable is set to
+ int result = putenv(kAtosMachPortEnvEntry);
+ CHECK_EQ(result, 0);
+ }
}
private:
bool StartSymbolizerSubprocess() override {
// Configure sandbox before starting atos process.
+
+ // Put the string command line argument in the object so that it outlives
+ // the call to GetArgV.
+ internal_snprintf(pid_str_, sizeof(pid_str_), "%d", internal_getpid());
+
+ if (SANITIZER_IOSSIM) {
+ // `atos` in the simulator is restricted in its ability to retrieve the
+ // task port for the target process (us) so we need to do extra work
+ // to pass our task port to it.
+ mach_port_t ports[]{mach_task_self()};
+ kern_return_t ret =
+ mach_ports_register(mach_task_self(), ports, /*count=*/1);
+ CHECK_EQ(ret, KERN_SUCCESS);
+
+ // Set environment variable that signals to `atos` that it should look
+ // for our task port. We can't call `setenv()` here because it might call
+ // malloc/realloc. To avoid that we instead update the
+ // `mach_port_env_var_entry_` variable with our current PID.
+ uptr count = internal_snprintf(kAtosMachPortEnvEntry,
+ sizeof(kAtosMachPortEnvEntry),
+ K_ATOS_ENV_VAR "=%s", pid_str_);
+ CHECK_GE(count, sizeof(K_ATOS_ENV_VAR) + internal_strlen(pid_str_));
+ // Document our assumption but without calling `getenv()` in normal
+ // builds.
+ DCHECK(getenv(K_ATOS_ENV_VAR));
+ DCHECK_EQ(internal_strcmp(getenv(K_ATOS_ENV_VAR), pid_str_), 0);
+ }
+
return SymbolizerProcess::StartSymbolizerSubprocess();
}
@@ -82,8 +133,14 @@ class AtosSymbolizerProcess : public SymbolizerProcess {
}
char pid_str_[16];
+ // Space for `\0` in `K_ATOS_ENV_VAR` is reused for `=`.
+ static_assert(sizeof(kAtosMachPortEnvEntry) ==
+ (sizeof(K_ATOS_ENV_VAR) + sizeof(pid_str_)),
+ "sizes should match");
};
+#undef K_ATOS_ENV_VAR
+
static bool ParseCommandOutput(const char *str, uptr addr, char **out_name,
char **out_module, char **out_file, uptr *line,
uptr *start_address) {
@@ -135,7 +192,7 @@ static bool ParseCommandOutput(const char *str, uptr addr, char **out_name,
}
AtosSymbolizer::AtosSymbolizer(const char *path, LowLevelAllocator *allocator)
- : process_(new(*allocator) AtosSymbolizerProcess(path, getpid())) {}
+ : process_(new (*allocator) AtosSymbolizerProcess(path)) {}
bool AtosSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) {
if (!process_) return false;
@@ -145,12 +202,29 @@ bool AtosSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) {
const char *buf = process_->SendCommand(command);
if (!buf) return false;
uptr line;
+ uptr start_address = AddressInfo::kUnknown;
if (!ParseCommandOutput(buf, addr, &stack->info.function, &stack->info.module,
- &stack->info.file, &line, nullptr)) {
+ &stack->info.file, &line, &start_address)) {
process_ = nullptr;
return false;
}
stack->info.line = (int)line;
+
+ if (start_address == AddressInfo::kUnknown) {
+ // Fallback to dladdr() to get function start address if atos doesn't report
+ // it.
+ Dl_info info;
+ int result = dladdr((const void *)addr, &info);
+ if (result)
+ start_address = reinterpret_cast<uptr>(info.dli_saddr);
+ }
+
+ // Only assig to `function_offset` if we were able to get the function's
+ // start address.
+ if (start_address != AddressInfo::kUnknown) {
+ CHECK(addr >= start_address);
+ stack->info.function_offset = addr - start_address;
+ }
return true;
}
@@ -168,6 +242,8 @@ bool AtosSymbolizer::SymbolizeData(uptr addr, DataInfo *info) {
return true;
}
+void AtosSymbolizer::LateInitialize() { process_->LateInitialize(); }
+
} // namespace __sanitizer
#endif // SANITIZER_MAC
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.h b/libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.h
index 68521375e64..8996131fc13 100644
--- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.h
+++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.h
@@ -35,6 +35,7 @@ class AtosSymbolizer : public SymbolizerTool {
bool SymbolizePC(uptr addr, SymbolizedStack *stack) override;
bool SymbolizeData(uptr addr, DataInfo *info) override;
+ void LateInitialize() override;
private:
AtosSymbolizerProcess *process_;
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_markup.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_markup.cpp
index 57b4d0c9d96..2963af95360 100644
--- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_markup.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_markup.cpp
@@ -94,7 +94,9 @@ Symbolizer *Symbolizer::PlatformInit() {
return new (symbolizer_allocator_) Symbolizer({});
}
-void Symbolizer::LateInitialize() { Symbolizer::GetOrInit(); }
+void Symbolizer::LateInitialize() {
+ Symbolizer::GetOrInit()->LateInitializeTools();
+}
void StartReportDeadlySignal() {}
void ReportDeadlySignal(const SignalContext &sig, u32 tid,
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp
index c123ecb1120..d7b931bc237 100644
--- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp
@@ -151,9 +151,19 @@ bool SymbolizerProcess::StartSymbolizerSubprocess() {
GetArgV(path_, argv);
pid_t pid;
+ // Report how symbolizer is being launched for debugging purposes.
+ if (Verbosity() >= 3) {
+ // Only use `Report` for first line so subsequent prints don't get prefixed
+ // with current PID.
+ Report("Launching Symbolizer process: ");
+ for (unsigned index = 0; index < kArgVMax && argv[index]; ++index)
+ Printf("%s ", argv[index]);
+ Printf("\n");
+ }
+
if (use_posix_spawn_) {
#if SANITIZER_MAC
- fd_t fd = internal_spawn(argv, &pid);
+ fd_t fd = internal_spawn(argv, const_cast<const char **>(GetEnvP()), &pid);
if (fd == kInvalidFd) {
Report("WARNING: failed to spawn external symbolizer (errno: %d)\n",
errno);
@@ -173,7 +183,7 @@ bool SymbolizerProcess::StartSymbolizerSubprocess() {
return false;
}
- pid = StartSubprocess(path_, argv, /* stdin */ outfd[0],
+ pid = StartSubprocess(path_, argv, GetEnvP(), /* stdin */ outfd[0],
/* stdout */ infd[1]);
if (pid < 0) {
internal_close(infd[0]);
@@ -478,7 +488,7 @@ Symbolizer *Symbolizer::PlatformInit() {
}
void Symbolizer::LateInitialize() {
- Symbolizer::GetOrInit();
+ Symbolizer::GetOrInit()->LateInitializeTools();
InitializeSwiftDemangler();
}
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cpp
index 2808779156e..373437e7ee2 100644
--- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cpp
@@ -310,7 +310,7 @@ Symbolizer *Symbolizer::PlatformInit() {
}
void Symbolizer::LateInitialize() {
- Symbolizer::GetOrInit();
+ Symbolizer::GetOrInit()->LateInitializeTools();
}
} // namespace __sanitizer
diff --git a/libsanitizer/sanitizer_common/sanitizer_syscalls_netbsd.inc b/libsanitizer/sanitizer_common/sanitizer_syscalls_netbsd.inc
index 69e59871874..02b7e11b167 100644
--- a/libsanitizer/sanitizer_common/sanitizer_syscalls_netbsd.inc
+++ b/libsanitizer/sanitizer_common/sanitizer_syscalls_netbsd.inc
@@ -42,7 +42,7 @@
// DO NOT EDIT! THIS FILE HAS BEEN GENERATED!
//
// Generated with: generate_netbsd_syscalls.awk
-// Generated date: 2019-11-01
+// Generated date: 2019-12-24
// Generated from: syscalls.master,v 1.296 2019/09/22 22:59:39 christos Exp
//
//===----------------------------------------------------------------------===//
@@ -323,6 +323,16 @@ PRE_SYSCALL(ptrace)
PRE_READ(addr_, struct_ptrace_ptrace_siginfo_struct_sz);
} else if (req_ == ptrace_pt_get_siginfo) {
PRE_WRITE(addr_, struct_ptrace_ptrace_siginfo_struct_sz);
+ } else if (req_ == ptrace_pt_lwpstatus) {
+ struct __sanitizer_ptrace_lwpstatus *addr =
+ (struct __sanitizer_ptrace_lwpstatus *)addr_;
+ PRE_READ(&addr->pl_lwpid, sizeof(__sanitizer_lwpid_t));
+ PRE_WRITE(addr, struct_ptrace_ptrace_lwpstatus_struct_sz);
+ } else if (req_ == ptrace_pt_lwpnext) {
+ struct __sanitizer_ptrace_lwpstatus *addr =
+ (struct __sanitizer_ptrace_lwpstatus *)addr_;
+ PRE_READ(&addr->pl_lwpid, sizeof(__sanitizer_lwpid_t));
+ PRE_WRITE(addr, struct_ptrace_ptrace_lwpstatus_struct_sz);
} else if (req_ == ptrace_pt_setregs) {
PRE_READ(addr_, struct_ptrace_reg_struct_sz);
} else if (req_ == ptrace_pt_getregs) {
@@ -366,6 +376,16 @@ POST_SYSCALL(ptrace)
POST_READ(addr_, struct_ptrace_ptrace_siginfo_struct_sz);
} else if (req_ == ptrace_pt_get_siginfo) {
POST_WRITE(addr_, struct_ptrace_ptrace_siginfo_struct_sz);
+ } else if (req_ == ptrace_pt_lwpstatus) {
+ struct __sanitizer_ptrace_lwpstatus *addr =
+ (struct __sanitizer_ptrace_lwpstatus *)addr_;
+ POST_READ(&addr->pl_lwpid, sizeof(__sanitizer_lwpid_t));
+ POST_WRITE(addr, struct_ptrace_ptrace_lwpstatus_struct_sz);
+ } else if (req_ == ptrace_pt_lwpnext) {
+ struct __sanitizer_ptrace_lwpstatus *addr =
+ (struct __sanitizer_ptrace_lwpstatus *)addr_;
+ POST_READ(&addr->pl_lwpid, sizeof(__sanitizer_lwpid_t));
+ POST_WRITE(addr, struct_ptrace_ptrace_lwpstatus_struct_sz);
} else if (req_ == ptrace_pt_setregs) {
POST_READ(addr_, struct_ptrace_reg_struct_sz);
} else if (req_ == ptrace_pt_getregs) {
diff --git a/libsanitizer/sanitizer_common/sanitizer_win.cpp b/libsanitizer/sanitizer_common/sanitizer_win.cpp
index 36dde49d870..fca15beb616 100644
--- a/libsanitizer/sanitizer_common/sanitizer_win.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_win.cpp
@@ -94,6 +94,10 @@ uptr internal_getpid() {
return GetProcessId(GetCurrentProcess());
}
+int internal_dlinfo(void *handle, int request, void *p) {
+ UNIMPLEMENTED();
+}
+
// In contrast to POSIX, on Windows GetCurrentThreadId()
// returns a system-unique identifier.
tid_t GetTid() {
@@ -787,7 +791,7 @@ uptr GetRSS() {
return counters.WorkingSetSize;
}
-void *internal_start_thread(void (*func)(void *arg), void *arg) { return 0; }
+void *internal_start_thread(void *(*func)(void *arg), void *arg) { return 0; }
void internal_join_thread(void *th) { }
// ---------------------- BlockingMutex ---------------- {{{1
@@ -1060,7 +1064,8 @@ char **GetEnviron() {
}
pid_t StartSubprocess(const char *program, const char *const argv[],
- fd_t stdin_fd, fd_t stdout_fd, fd_t stderr_fd) {
+ const char *const envp[], fd_t stdin_fd, fd_t stdout_fd,
+ fd_t stderr_fd) {
// FIXME: implement on this platform
// Should be implemented based on
// SymbolizerProcess::StarAtSymbolizerSubprocess
diff --git a/libsanitizer/tsan/tsan_clock.cpp b/libsanitizer/tsan/tsan_clock.cpp
index 4b7aa0653da..c91b29cb22b 100644
--- a/libsanitizer/tsan/tsan_clock.cpp
+++ b/libsanitizer/tsan/tsan_clock.cpp
@@ -30,6 +30,14 @@
// dst->clock[i] = max(dst->clock[i], clock[i]);
// }
//
+// void ThreadClock::releaseStoreAcquire(SyncClock *sc) const {
+// for (int i = 0; i < kMaxThreads; i++) {
+// tmp = clock[i];
+// clock[i] = max(clock[i], sc->clock[i]);
+// sc->clock[i] = tmp;
+// }
+// }
+//
// void ThreadClock::ReleaseStore(SyncClock *dst) const {
// for (int i = 0; i < kMaxThreads; i++)
// dst->clock[i] = clock[i];
@@ -107,13 +115,14 @@ static void UnrefClockBlock(ClockCache *c, u32 idx, uptr blocks) {
ThreadClock::ThreadClock(unsigned tid, unsigned reused)
: tid_(tid)
, reused_(reused + 1) // 0 has special meaning
+ , last_acquire_()
+ , global_acquire_()
, cached_idx_()
, cached_size_()
, cached_blocks_() {
CHECK_LT(tid, kMaxTidInClock);
CHECK_EQ(reused_, ((u64)reused_ << kClkBits) >> kClkBits);
nclk_ = tid_ + 1;
- last_acquire_ = 0;
internal_memset(clk_, 0, sizeof(clk_));
}
@@ -177,6 +186,49 @@ void ThreadClock::acquire(ClockCache *c, SyncClock *src) {
}
}
+void ThreadClock::releaseStoreAcquire(ClockCache *c, SyncClock *sc) {
+ DCHECK_LE(nclk_, kMaxTid);
+ DCHECK_LE(sc->size_, kMaxTid);
+
+ if (sc->size_ == 0) {
+ // ReleaseStore will correctly set release_store_tid_,
+ // which can be important for future operations.
+ ReleaseStore(c, sc);
+ return;
+ }
+
+ nclk_ = max(nclk_, (uptr) sc->size_);
+
+ // Check if we need to resize sc.
+ if (sc->size_ < nclk_)
+ sc->Resize(c, nclk_);
+
+ bool acquired = false;
+
+ sc->Unshare(c);
+ // Update sc->clk_.
+ sc->FlushDirty();
+ uptr i = 0;
+ for (ClockElem &ce : *sc) {
+ u64 tmp = clk_[i];
+ if (clk_[i] < ce.epoch) {
+ clk_[i] = ce.epoch;
+ acquired = true;
+ }
+ ce.epoch = tmp;
+ ce.reused = 0;
+ i++;
+ }
+ sc->release_store_tid_ = kInvalidTid;
+ sc->release_store_reused_ = 0;
+
+ if (acquired) {
+ CPP_STAT_INC(StatClockAcquiredSomething);
+ last_acquire_ = clk_[tid_];
+ ResetCached(c);
+ }
+}
+
void ThreadClock::release(ClockCache *c, SyncClock *dst) {
DCHECK_LE(nclk_, kMaxTid);
DCHECK_LE(dst->size_, kMaxTid);
@@ -196,7 +248,7 @@ void ThreadClock::release(ClockCache *c, SyncClock *dst) {
// Check if we had not acquired anything from other threads
// since the last release on dst. If so, we need to update
// only dst->elem(tid_).
- if (dst->elem(tid_).epoch > last_acquire_) {
+ if (!HasAcquiredAfterRelease(dst)) {
UpdateCurrentThread(c, dst);
if (dst->release_store_tid_ != tid_ ||
dst->release_store_reused_ != reused_)
@@ -222,8 +274,6 @@ void ThreadClock::release(ClockCache *c, SyncClock *dst) {
// Clear 'acquired' flag in the remaining elements.
if (nclk_ < dst->size_)
CPP_STAT_INC(StatClockReleaseClearTail);
- for (uptr i = nclk_; i < dst->size_; i++)
- dst->elem(i).reused = 0;
dst->release_store_tid_ = kInvalidTid;
dst->release_store_reused_ = 0;
// If we've acquired dst, remember this fact,
@@ -269,7 +319,7 @@ void ThreadClock::ReleaseStore(ClockCache *c, SyncClock *dst) {
if (dst->release_store_tid_ == tid_ &&
dst->release_store_reused_ == reused_ &&
- dst->elem(tid_).epoch > last_acquire_) {
+ !HasAcquiredAfterRelease(dst)) {
CPP_STAT_INC(StatClockStoreFast);
UpdateCurrentThread(c, dst);
return;
@@ -351,6 +401,14 @@ bool ThreadClock::IsAlreadyAcquired(const SyncClock *src) const {
return true;
}
+// Checks whether the current thread has acquired anything
+// from other clocks after releasing to dst (directly or indirectly).
+bool ThreadClock::HasAcquiredAfterRelease(const SyncClock *dst) const {
+ const u64 my_epoch = dst->elem(tid_).epoch;
+ return my_epoch <= last_acquire_ ||
+ my_epoch <= atomic_load_relaxed(&global_acquire_);
+}
+
// Sets a single element in the vector clock.
// This function is called only from weird places like AcquireGlobal.
void ThreadClock::set(ClockCache *c, unsigned tid, u64 v) {
diff --git a/libsanitizer/tsan/tsan_clock.h b/libsanitizer/tsan/tsan_clock.h
index 6a1d15a2a16..736cdae06ba 100644
--- a/libsanitizer/tsan/tsan_clock.h
+++ b/libsanitizer/tsan/tsan_clock.h
@@ -134,10 +134,12 @@ class ThreadClock {
uptr size() const;
void acquire(ClockCache *c, SyncClock *src);
+ void releaseStoreAcquire(ClockCache *c, SyncClock *src);
void release(ClockCache *c, SyncClock *dst);
void acq_rel(ClockCache *c, SyncClock *dst);
void ReleaseStore(ClockCache *c, SyncClock *dst);
void ResetCached(ClockCache *c);
+ void NoteGlobalAcquire(u64 v);
void DebugReset();
void DebugDump(int(*printf)(const char *s, ...));
@@ -150,6 +152,53 @@ class ThreadClock {
// Current thread time when it acquired something from other threads.
u64 last_acquire_;
+ // Last time another thread has done a global acquire of this thread's clock.
+ // It helps to avoid problem described in:
+ // https://github.com/golang/go/issues/39186
+ // See test/tsan/java_finalizer2.cpp for a regression test.
+ // Note the failuire is _extremely_ hard to hit, so if you are trying
+ // to reproduce it, you may want to run something like:
+ // $ go get golang.org/x/tools/cmd/stress
+ // $ stress -p=64 ./a.out
+ //
+ // The crux of the problem is roughly as follows.
+ // A number of O(1) optimizations in the clocks algorithm assume proper
+ // transitive cumulative propagation of clock values. The AcquireGlobal
+ // operation may produce an inconsistent non-linearazable view of
+ // thread clocks. Namely, it may acquire a later value from a thread
+ // with a higher ID, but fail to acquire an earlier value from a thread
+ // with a lower ID. If a thread that executed AcquireGlobal then releases
+ // to a sync clock, it will spoil the sync clock with the inconsistent
+ // values. If another thread later releases to the sync clock, the optimized
+ // algorithm may break.
+ //
+ // The exact sequence of events that leads to the failure.
+ // - thread 1 executes AcquireGlobal
+ // - thread 1 acquires value 1 for thread 2
+ // - thread 2 increments clock to 2
+ // - thread 2 releases to sync object 1
+ // - thread 3 at time 1
+ // - thread 3 acquires from sync object 1
+ // - thread 3 increments clock to 2
+ // - thread 1 acquires value 2 for thread 3
+ // - thread 1 releases to sync object 2
+ // - sync object 2 clock has 1 for thread 2 and 2 for thread 3
+ // - thread 3 releases to sync object 2
+ // - thread 3 sees value 2 in the clock for itself
+ // and decides that it has already released to the clock
+ // and did not acquire anything from other threads after that
+ // (the last_acquire_ check in release operation)
+ // - thread 3 does not update the value for thread 2 in the clock from 1 to 2
+ // - thread 4 acquires from sync object 2
+ // - thread 4 detects a false race with thread 2
+ // as it should have been synchronized with thread 2 up to time 2,
+ // but because of the broken clock it is now synchronized only up to time 1
+ //
+ // The global_acquire_ value helps to prevent this scenario.
+ // Namely, thread 3 will not trust any own clock values up to global_acquire_
+ // for the purposes of the last_acquire_ optimization.
+ atomic_uint64_t global_acquire_;
+
// Cached SyncClock (without dirty entries and release_store_tid_).
// We reuse it for subsequent store-release operations without intervening
// acquire operations. Since it is shared (and thus constant), clock value
@@ -164,6 +213,7 @@ class ThreadClock {
u64 clk_[kMaxTidInClock]; // Fixed size vector clock.
bool IsAlreadyAcquired(const SyncClock *src) const;
+ bool HasAcquiredAfterRelease(const SyncClock *dst) const;
void UpdateCurrentThread(ClockCache *c, SyncClock *dst) const;
};
@@ -185,6 +235,14 @@ ALWAYS_INLINE uptr ThreadClock::size() const {
return nclk_;
}
+ALWAYS_INLINE void ThreadClock::NoteGlobalAcquire(u64 v) {
+ // Here we rely on the fact that AcquireGlobal is protected by
+ // ThreadRegistryLock, thus only one thread at a time executes it
+ // and values passed to this function should not go backwards.
+ CHECK_LE(atomic_load_relaxed(&global_acquire_), v);
+ atomic_store_relaxed(&global_acquire_, v);
+}
+
ALWAYS_INLINE SyncClock::Iter SyncClock::begin() {
return Iter(this);
}
diff --git a/libsanitizer/tsan/tsan_interceptors_posix.cpp b/libsanitizer/tsan/tsan_interceptors_posix.cpp
index 8aea1e4ec05..718957c3703 100644
--- a/libsanitizer/tsan/tsan_interceptors_posix.cpp
+++ b/libsanitizer/tsan/tsan_interceptors_posix.cpp
@@ -891,13 +891,16 @@ void DestroyThreadState() {
ThreadFinish(thr);
ProcUnwire(proc, thr);
ProcDestroy(proc);
+ DTLS_Destroy();
+ cur_thread_finalize();
+}
+
+void PlatformCleanUpThreadState(ThreadState *thr) {
ThreadSignalContext *sctx = thr->signal_ctx;
if (sctx) {
thr->signal_ctx = 0;
UnmapOrDie(sctx, sizeof(*sctx));
}
- DTLS_Destroy();
- cur_thread_finalize();
}
} // namespace __tsan
@@ -1016,7 +1019,7 @@ TSAN_INTERCEPTOR(int, pthread_create,
TSAN_INTERCEPTOR(int, pthread_join, void *th, void **ret) {
SCOPED_INTERCEPTOR_RAW(pthread_join, th, ret);
- int tid = ThreadTid(thr, pc, (uptr)th);
+ int tid = ThreadConsumeTid(thr, pc, (uptr)th);
ThreadIgnoreBegin(thr, pc);
int res = BLOCK_REAL(pthread_join)(th, ret);
ThreadIgnoreEnd(thr, pc);
@@ -1029,8 +1032,8 @@ TSAN_INTERCEPTOR(int, pthread_join, void *th, void **ret) {
DEFINE_REAL_PTHREAD_FUNCTIONS
TSAN_INTERCEPTOR(int, pthread_detach, void *th) {
- SCOPED_TSAN_INTERCEPTOR(pthread_detach, th);
- int tid = ThreadTid(thr, pc, (uptr)th);
+ SCOPED_INTERCEPTOR_RAW(pthread_detach, th);
+ int tid = ThreadConsumeTid(thr, pc, (uptr)th);
int res = REAL(pthread_detach)(th);
if (res == 0) {
ThreadDetach(thr, pc, tid);
@@ -1050,8 +1053,8 @@ TSAN_INTERCEPTOR(void, pthread_exit, void *retval) {
#if SANITIZER_LINUX
TSAN_INTERCEPTOR(int, pthread_tryjoin_np, void *th, void **ret) {
- SCOPED_TSAN_INTERCEPTOR(pthread_tryjoin_np, th, ret);
- int tid = ThreadTid(thr, pc, (uptr)th);
+ SCOPED_INTERCEPTOR_RAW(pthread_tryjoin_np, th, ret);
+ int tid = ThreadConsumeTid(thr, pc, (uptr)th);
ThreadIgnoreBegin(thr, pc);
int res = REAL(pthread_tryjoin_np)(th, ret);
ThreadIgnoreEnd(thr, pc);
@@ -1064,8 +1067,8 @@ TSAN_INTERCEPTOR(int, pthread_tryjoin_np, void *th, void **ret) {
TSAN_INTERCEPTOR(int, pthread_timedjoin_np, void *th, void **ret,
const struct timespec *abstime) {
- SCOPED_TSAN_INTERCEPTOR(pthread_timedjoin_np, th, ret, abstime);
- int tid = ThreadTid(thr, pc, (uptr)th);
+ SCOPED_INTERCEPTOR_RAW(pthread_timedjoin_np, th, ret, abstime);
+ int tid = ThreadConsumeTid(thr, pc, (uptr)th);
ThreadIgnoreBegin(thr, pc);
int res = BLOCK_REAL(pthread_timedjoin_np)(th, ret, abstime);
ThreadIgnoreEnd(thr, pc);
diff --git a/libsanitizer/tsan/tsan_platform.h b/libsanitizer/tsan/tsan_platform.h
index 63eb14fcd34..7256d64e507 100644
--- a/libsanitizer/tsan/tsan_platform.h
+++ b/libsanitizer/tsan/tsan_platform.h
@@ -1021,6 +1021,7 @@ int call_pthread_cancel_with_cleanup(int(*fn)(void *c, void *m,
void(*cleanup)(void *arg), void *arg);
void DestroyThreadState();
+void PlatformCleanUpThreadState(ThreadState *thr);
} // namespace __tsan
diff --git a/libsanitizer/tsan/tsan_platform_mac.cpp b/libsanitizer/tsan/tsan_platform_mac.cpp
index 326ca8532e5..f92ecc5e40f 100644
--- a/libsanitizer/tsan/tsan_platform_mac.cpp
+++ b/libsanitizer/tsan/tsan_platform_mac.cpp
@@ -19,6 +19,7 @@
#include "sanitizer_common/sanitizer_libc.h"
#include "sanitizer_common/sanitizer_posix.h"
#include "sanitizer_common/sanitizer_procmaps.h"
+#include "sanitizer_common/sanitizer_ptrauth.h"
#include "sanitizer_common/sanitizer_stackdepot.h"
#include "tsan_platform.h"
#include "tsan_rtl.h"
@@ -75,9 +76,14 @@ static uptr main_thread_identity = 0;
ALIGNED(64) static char main_thread_state[sizeof(ThreadState)];
static ThreadState *main_thread_state_loc = (ThreadState *)main_thread_state;
+// We cannot use pthread_self() before libpthread has been initialized. Our
+// current heuristic for guarding this is checking `main_thread_identity` which
+// is only assigned in `__tsan::InitializePlatform`.
static ThreadState **cur_thread_location() {
+ if (main_thread_identity == 0)
+ return &main_thread_state_loc;
uptr thread_identity = (uptr)pthread_self();
- if (thread_identity == main_thread_identity || main_thread_identity == 0)
+ if (thread_identity == main_thread_identity)
return &main_thread_state_loc;
return (ThreadState **)MemToShadow(thread_identity);
}
@@ -269,6 +275,8 @@ void InitializePlatform() {
uptr ExtractLongJmpSp(uptr *env) {
uptr mangled_sp = env[LONG_JMP_SP_ENV_SLOT];
uptr sp = mangled_sp ^ longjmp_xor_key;
+ sp = (uptr)ptrauth_auth_data((void *)sp, ptrauth_key_asdb,
+ ptrauth_string_discriminator("sp"));
return sp;
}
diff --git a/libsanitizer/tsan/tsan_rtl.cpp b/libsanitizer/tsan/tsan_rtl.cpp
index 3f3c0cce119..13c9b770f50 100644
--- a/libsanitizer/tsan/tsan_rtl.cpp
+++ b/libsanitizer/tsan/tsan_rtl.cpp
@@ -144,7 +144,7 @@ static void MemoryProfiler(Context *ctx, fd_t fd, int i) {
WriteToFile(fd, buf.data(), internal_strlen(buf.data()));
}
-static void BackgroundThread(void *arg) {
+static void *BackgroundThread(void *arg) {
// This is a non-initialized non-user thread, nothing to see here.
// We don't use ScopedIgnoreInterceptors, because we want ignores to be
// enabled even when the thread function exits (e.g. during pthread thread
@@ -220,6 +220,7 @@ static void BackgroundThread(void *arg) {
}
}
}
+ return nullptr;
}
static void StartBackgroundThread() {
@@ -494,14 +495,23 @@ int Finalize(ThreadState *thr) {
void ForkBefore(ThreadState *thr, uptr pc) {
ctx->thread_registry->Lock();
ctx->report_mtx.Lock();
+ // Ignore memory accesses in the pthread_atfork callbacks.
+ // If any of them triggers a data race we will deadlock
+ // on the report_mtx.
+ // We could ignore interceptors and sync operations as well,
+ // but so far it's unclear if it will do more good or harm.
+ // Unnecessarily ignoring things can lead to false positives later.
+ ThreadIgnoreBegin(thr, pc);
}
void ForkParentAfter(ThreadState *thr, uptr pc) {
+ ThreadIgnoreEnd(thr, pc); // Begin is in ForkBefore.
ctx->report_mtx.Unlock();
ctx->thread_registry->Unlock();
}
void ForkChildAfter(ThreadState *thr, uptr pc) {
+ ThreadIgnoreEnd(thr, pc); // Begin is in ForkBefore.
ctx->report_mtx.Unlock();
ctx->thread_registry->Unlock();
diff --git a/libsanitizer/tsan/tsan_rtl.h b/libsanitizer/tsan/tsan_rtl.h
index c38fc43a9f8..d3bb61ff87d 100644
--- a/libsanitizer/tsan/tsan_rtl.h
+++ b/libsanitizer/tsan/tsan_rtl.h
@@ -775,7 +775,7 @@ int ThreadCreate(ThreadState *thr, uptr pc, uptr uid, bool detached);
void ThreadStart(ThreadState *thr, int tid, tid_t os_id,
ThreadType thread_type);
void ThreadFinish(ThreadState *thr);
-int ThreadTid(ThreadState *thr, uptr pc, uptr uid);
+int ThreadConsumeTid(ThreadState *thr, uptr pc, uptr uid);
void ThreadJoin(ThreadState *thr, uptr pc, int tid);
void ThreadDetach(ThreadState *thr, uptr pc, int tid);
void ThreadFinalize(ThreadState *thr);
@@ -813,10 +813,12 @@ void Acquire(ThreadState *thr, uptr pc, uptr addr);
// approximation of the actual required synchronization.
void AcquireGlobal(ThreadState *thr, uptr pc);
void Release(ThreadState *thr, uptr pc, uptr addr);
+void ReleaseStoreAcquire(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 ReleaseStoreAcquireImpl(ThreadState *thr, uptr pc, SyncClock *c);
void ReleaseStoreImpl(ThreadState *thr, uptr pc, SyncClock *c);
void AcquireReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c);
diff --git a/libsanitizer/tsan/tsan_rtl_mutex.cpp b/libsanitizer/tsan/tsan_rtl_mutex.cpp
index ce6e7cb2c4e..ebd0d722181 100644
--- a/libsanitizer/tsan/tsan_rtl_mutex.cpp
+++ b/libsanitizer/tsan/tsan_rtl_mutex.cpp
@@ -415,8 +415,10 @@ static void UpdateClockCallback(ThreadContextBase *tctx_base, void *arg) {
ThreadState *thr = reinterpret_cast<ThreadState*>(arg);
ThreadContext *tctx = static_cast<ThreadContext*>(tctx_base);
u64 epoch = tctx->epoch1;
- if (tctx->status == ThreadStatusRunning)
+ if (tctx->status == ThreadStatusRunning) {
epoch = tctx->thr->fast_state.epoch();
+ tctx->thr->clock.NoteGlobalAcquire(epoch);
+ }
thr->clock.set(&thr->proc()->clock_cache, tctx->tid, epoch);
}
@@ -429,6 +431,18 @@ void AcquireGlobal(ThreadState *thr, uptr pc) {
UpdateClockCallback, thr);
}
+void ReleaseStoreAcquire(ThreadState *thr, uptr pc, uptr addr) {
+ DPrintf("#%d: ReleaseStoreAcquire %zx\n", thr->tid, addr);
+ if (thr->ignore_sync)
+ return;
+ SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true);
+ thr->fast_state.IncrementEpoch();
+ // Can't increment epoch w/o writing to the trace as well.
+ TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0);
+ ReleaseStoreAcquireImpl(thr, pc, &s->clock);
+ s->mtx.Unlock();
+}
+
void Release(ThreadState *thr, uptr pc, uptr addr) {
DPrintf("#%d: Release %zx\n", thr->tid, addr);
if (thr->ignore_sync)
@@ -482,6 +496,15 @@ void AcquireImpl(ThreadState *thr, uptr pc, SyncClock *c) {
StatInc(thr, StatSyncAcquire);
}
+void ReleaseStoreAcquireImpl(ThreadState *thr, uptr pc, SyncClock *c) {
+ if (thr->ignore_sync)
+ return;
+ thr->clock.set(thr->fast_state.epoch());
+ thr->fast_synch_epoch = thr->fast_state.epoch();
+ thr->clock.releaseStoreAcquire(&thr->proc()->clock_cache, c);
+ StatInc(thr, StatSyncReleaseStoreAcquire);
+}
+
void ReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c) {
if (thr->ignore_sync)
return;
diff --git a/libsanitizer/tsan/tsan_rtl_ppc64.S b/libsanitizer/tsan/tsan_rtl_ppc64.S
index 9e533a71a9c..8285e21aa1e 100644
--- a/libsanitizer/tsan/tsan_rtl_ppc64.S
+++ b/libsanitizer/tsan/tsan_rtl_ppc64.S
@@ -1,6 +1,5 @@
#include "tsan_ppc_regs.h"
- .machine altivec
.section .text
.hidden __tsan_setjmp
.globl _setjmp
diff --git a/libsanitizer/tsan/tsan_rtl_thread.cpp b/libsanitizer/tsan/tsan_rtl_thread.cpp
index 0ac1ee99c47..d80146735ea 100644
--- a/libsanitizer/tsan/tsan_rtl_thread.cpp
+++ b/libsanitizer/tsan/tsan_rtl_thread.cpp
@@ -144,6 +144,9 @@ void ThreadContext::OnFinished() {
thr->clock.ResetCached(&thr->proc()->clock_cache);
#if !SANITIZER_GO
thr->last_sleep_clock.ResetCached(&thr->proc()->clock_cache);
+#endif
+#if !SANITIZER_GO
+ PlatformCleanUpThreadState(thr);
#endif
thr->~ThreadState();
#if TSAN_COLLECT_STATS
@@ -285,19 +288,34 @@ void ThreadFinish(ThreadState *thr) {
ctx->thread_registry->FinishThread(thr->tid);
}
-static bool FindThreadByUid(ThreadContextBase *tctx, void *arg) {
- uptr uid = (uptr)arg;
- if (tctx->user_id == uid && tctx->status != ThreadStatusInvalid) {
+struct ConsumeThreadContext {
+ uptr uid;
+ ThreadContextBase *tctx;
+};
+
+static bool ConsumeThreadByUid(ThreadContextBase *tctx, void *arg) {
+ ConsumeThreadContext *findCtx = (ConsumeThreadContext *)arg;
+ if (tctx->user_id == findCtx->uid && tctx->status != ThreadStatusInvalid) {
+ if (findCtx->tctx) {
+ // Ensure that user_id is unique. If it's not the case we are screwed.
+ // Something went wrong before, but now there is no way to recover.
+ // Returning a wrong thread is not an option, it may lead to very hard
+ // to debug false positives (e.g. if we join a wrong thread).
+ Report("ThreadSanitizer: dup thread with used id 0x%zx\n", findCtx->uid);
+ Die();
+ }
+ findCtx->tctx = tctx;
tctx->user_id = 0;
- return true;
}
return false;
}
-int ThreadTid(ThreadState *thr, uptr pc, uptr uid) {
- int res = ctx->thread_registry->FindThread(FindThreadByUid, (void*)uid);
- DPrintf("#%d: ThreadTid uid=%zu tid=%d\n", thr->tid, uid, res);
- return res;
+int ThreadConsumeTid(ThreadState *thr, uptr pc, uptr uid) {
+ ConsumeThreadContext findCtx = {uid, nullptr};
+ ctx->thread_registry->FindThread(ConsumeThreadByUid, &findCtx);
+ int tid = findCtx.tctx ? findCtx.tctx->tid : ThreadRegistry::kUnknownTid;
+ DPrintf("#%d: ThreadTid uid=%zu tid=%d\n", thr->tid, uid, tid);
+ return tid;
}
void ThreadJoin(ThreadState *thr, uptr pc, int tid) {
diff --git a/libsanitizer/tsan/tsan_stat.h b/libsanitizer/tsan/tsan_stat.h
index 94e18bc66df..8b26a59bb2e 100644
--- a/libsanitizer/tsan/tsan_stat.h
+++ b/libsanitizer/tsan/tsan_stat.h
@@ -68,6 +68,7 @@ enum StatType {
StatSyncDestroyed,
StatSyncAcquire,
StatSyncRelease,
+ StatSyncReleaseStoreAcquire,
// Clocks - acquire.
StatClockAcquire,
diff --git a/libsanitizer/ubsan/ubsan_checks.inc b/libsanitizer/ubsan/ubsan_checks.inc
index 33a8dfcde02..2c1529a7d92 100644
--- a/libsanitizer/ubsan/ubsan_checks.inc
+++ b/libsanitizer/ubsan/ubsan_checks.inc
@@ -18,6 +18,8 @@
UBSAN_CHECK(GenericUB, "undefined-behavior", "undefined")
UBSAN_CHECK(NullPointerUse, "null-pointer-use", "null")
+UBSAN_CHECK(NullPointerUseWithNullability, "null-pointer-use",
+ "nullability-assign")
UBSAN_CHECK(NullptrWithOffset, "nullptr-with-offset", "pointer-overflow")
UBSAN_CHECK(NullptrWithNonZeroOffset, "nullptr-with-nonzero-offset",
"pointer-overflow")
@@ -59,6 +61,10 @@ UBSAN_CHECK(InvalidEnumLoad, "invalid-enum-load", "enum")
UBSAN_CHECK(FunctionTypeMismatch, "function-type-mismatch", "function")
UBSAN_CHECK(InvalidNullReturn, "invalid-null-return",
"returns-nonnull-attribute")
+UBSAN_CHECK(InvalidNullReturnWithNullability, "invalid-null-return",
+ "nullability-return")
UBSAN_CHECK(InvalidNullArgument, "invalid-null-argument", "nonnull-attribute")
+UBSAN_CHECK(InvalidNullArgumentWithNullability, "invalid-null-argument",
+ "nullability-arg")
UBSAN_CHECK(DynamicTypeMismatch, "dynamic-type-mismatch", "vptr")
UBSAN_CHECK(CFIBadType, "cfi-bad-type", "cfi")
diff --git a/libsanitizer/ubsan/ubsan_flags.cpp b/libsanitizer/ubsan/ubsan_flags.cpp
index 80de2a6d101..721c2273f13 100644
--- a/libsanitizer/ubsan/ubsan_flags.cpp
+++ b/libsanitizer/ubsan/ubsan_flags.cpp
@@ -54,7 +54,6 @@ void InitializeFlags() {
{
CommonFlags cf;
cf.CopyFrom(*common_flags());
- cf.print_summary = false;
cf.external_symbolizer_path = GetFlag("UBSAN_SYMBOLIZER_PATH");
OverrideCommonFlags(cf);
}
diff --git a/libsanitizer/ubsan/ubsan_handlers.cpp b/libsanitizer/ubsan/ubsan_handlers.cpp
index 0ddbb50c26c..7f6a46fb6cf 100644
--- a/libsanitizer/ubsan/ubsan_handlers.cpp
+++ b/libsanitizer/ubsan/ubsan_handlers.cpp
@@ -36,6 +36,45 @@ bool ignoreReport(SourceLocation SLoc, ReportOptions Opts, ErrorType ET) {
return SLoc.isDisabled() || IsPCSuppressed(ET, Opts.pc, SLoc.getFilename());
}
+/// Situations in which we might emit a check for the suitability of a
+/// pointer or glvalue. Needs to be kept in sync with CodeGenFunction.h in
+/// clang.
+enum TypeCheckKind {
+ /// Checking the operand of a load. Must be suitably sized and aligned.
+ TCK_Load,
+ /// Checking the destination of a store. Must be suitably sized and aligned.
+ TCK_Store,
+ /// Checking the bound value in a reference binding. Must be suitably sized
+ /// and aligned, but is not required to refer to an object (until the
+ /// reference is used), per core issue 453.
+ TCK_ReferenceBinding,
+ /// Checking the object expression in a non-static data member access. Must
+ /// be an object within its lifetime.
+ TCK_MemberAccess,
+ /// Checking the 'this' pointer for a call to a non-static member function.
+ /// Must be an object within its lifetime.
+ TCK_MemberCall,
+ /// Checking the 'this' pointer for a constructor call.
+ TCK_ConstructorCall,
+ /// Checking the operand of a static_cast to a derived pointer type. Must be
+ /// null or an object within its lifetime.
+ TCK_DowncastPointer,
+ /// Checking the operand of a static_cast to a derived reference type. Must
+ /// be an object within its lifetime.
+ TCK_DowncastReference,
+ /// Checking the operand of a cast to a base object. Must be suitably sized
+ /// and aligned.
+ TCK_Upcast,
+ /// Checking the operand of a cast to a virtual base object. Must be an
+ /// object within its lifetime.
+ TCK_UpcastToVirtualBase,
+ /// Checking the value assigned to a _Nonnull pointer. Must not be null.
+ TCK_NonnullAssign,
+ /// Checking the operand of a dynamic_cast or a typeid expression. Must be
+ /// null or an object within its lifetime.
+ TCK_DynamicOperation
+};
+
const char *TypeCheckKinds[] = {
"load of", "store to", "reference binding to", "member access within",
"member call on", "constructor call on", "downcast of", "downcast of",
@@ -50,7 +89,9 @@ static void handleTypeMismatchImpl(TypeMismatchData *Data, ValueHandle Pointer,
uptr Alignment = (uptr)1 << Data->LogAlignment;
ErrorType ET;
if (!Pointer)
- ET = ErrorType::NullPointerUse;
+ ET = (Data->TypeCheckKind == TCK_NonnullAssign)
+ ? ErrorType::NullPointerUseWithNullability
+ : ErrorType::NullPointerUse;
else if (Pointer & (Alignment - 1))
ET = ErrorType::MisalignedPointerUse;
else
@@ -71,6 +112,7 @@ static void handleTypeMismatchImpl(TypeMismatchData *Data, ValueHandle Pointer,
switch (ET) {
case ErrorType::NullPointerUse:
+ case ErrorType::NullPointerUseWithNullability:
Diag(Loc, DL_Error, ET, "%0 null pointer of type %1")
<< TypeCheckKinds[Data->TypeCheckKind] << Data->Type;
break;
@@ -604,7 +646,8 @@ static void handleNonNullReturn(NonNullReturnData *Data, SourceLocation *LocPtr,
UNREACHABLE("source location pointer is null!");
SourceLocation Loc = LocPtr->acquire();
- ErrorType ET = ErrorType::InvalidNullReturn;
+ ErrorType ET = IsAttr ? ErrorType::InvalidNullReturn
+ : ErrorType::InvalidNullReturnWithNullability;
if (ignoreReport(Loc, Opts, ET))
return;
@@ -648,7 +691,8 @@ void __ubsan::__ubsan_handle_nullability_return_v1_abort(
static void handleNonNullArg(NonNullArgData *Data, ReportOptions Opts,
bool IsAttr) {
SourceLocation Loc = Data->Loc.acquire();
- ErrorType ET = ErrorType::InvalidNullArgument;
+ ErrorType ET = IsAttr ? ErrorType::InvalidNullArgument
+ : ErrorType::InvalidNullArgumentWithNullability;
if (ignoreReport(Loc, Opts, ET))
return;
@@ -819,21 +863,6 @@ void __ubsan_handle_cfi_bad_type(CFICheckFailData *Data, ValueHandle Vtable,
} // namespace __ubsan
-void __ubsan::__ubsan_handle_cfi_bad_icall(CFIBadIcallData *CallData,
- ValueHandle Function) {
- GET_REPORT_OPTIONS(false);
- CFICheckFailData Data = {CFITCK_ICall, CallData->Loc, CallData->Type};
- handleCFIBadIcall(&Data, Function, Opts);
-}
-
-void __ubsan::__ubsan_handle_cfi_bad_icall_abort(CFIBadIcallData *CallData,
- ValueHandle Function) {
- GET_REPORT_OPTIONS(true);
- CFICheckFailData Data = {CFITCK_ICall, CallData->Loc, CallData->Type};
- handleCFIBadIcall(&Data, Function, Opts);
- Die();
-}
-
void __ubsan::__ubsan_handle_cfi_check_fail(CFICheckFailData *Data,
ValueHandle Value,
uptr ValidVtable) {
diff --git a/libsanitizer/ubsan/ubsan_handlers.h b/libsanitizer/ubsan/ubsan_handlers.h
index eba1cf918fc..22ca9642238 100644
--- a/libsanitizer/ubsan/ubsan_handlers.h
+++ b/libsanitizer/ubsan/ubsan_handlers.h
@@ -207,20 +207,12 @@ enum CFITypeCheckKind : unsigned char {
CFITCK_VMFCall,
};
-struct CFIBadIcallData {
- SourceLocation Loc;
- const TypeDescriptor &Type;
-};
-
struct CFICheckFailData {
CFITypeCheckKind CheckKind;
SourceLocation Loc;
const TypeDescriptor &Type;
};
-/// \brief Handle control flow integrity failure for indirect function calls.
-RECOVERABLE(cfi_bad_icall, CFIBadIcallData *Data, ValueHandle Function)
-
/// \brief Handle control flow integrity failures.
RECOVERABLE(cfi_check_fail, CFICheckFailData *Data, ValueHandle Function,
uptr VtableIsValid)
diff --git a/libsanitizer/ubsan/ubsan_init.cpp b/libsanitizer/ubsan/ubsan_init.cpp
index 1a3b7d37267..e0be5a72ec4 100644
--- a/libsanitizer/ubsan/ubsan_init.cpp
+++ b/libsanitizer/ubsan/ubsan_init.cpp
@@ -37,10 +37,12 @@ static void CommonStandaloneInit() {
SanitizerToolName = GetSanititizerToolName();
CacheBinaryName();
InitializeFlags();
+ __sanitizer::InitializePlatformEarly();
__sanitizer_set_report_path(common_flags()->log_path);
AndroidLogInit();
InitializeCoverage(common_flags()->coverage, common_flags()->coverage_dir);
CommonInit();
+ Symbolizer::LateInitialize();
}
void __ubsan::InitAsStandalone() {
diff --git a/libsanitizer/ubsan/ubsan_platform.h b/libsanitizer/ubsan/ubsan_platform.h
index 58aabbe67b5..71d7fb18c9b 100644
--- a/libsanitizer/ubsan/ubsan_platform.h
+++ b/libsanitizer/ubsan/ubsan_platform.h
@@ -12,7 +12,6 @@
#ifndef UBSAN_PLATFORM_H
#define UBSAN_PLATFORM_H
-#ifndef CAN_SANITIZE_UB
// Other platforms should be easy to add, and probably work as-is.
#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || \
defined(__NetBSD__) || defined(__OpenBSD__) || \
@@ -22,6 +21,5 @@
#else
# define CAN_SANITIZE_UB 0
#endif
-#endif //CAN_SANITIZE_UB
#endif
diff --git a/libsanitizer/ubsan/ubsan_type_hash_itanium.cpp b/libsanitizer/ubsan/ubsan_type_hash_itanium.cpp
index 97846d4dd43..4f1708ba190 100644
--- a/libsanitizer/ubsan/ubsan_type_hash_itanium.cpp
+++ b/libsanitizer/ubsan/ubsan_type_hash_itanium.cpp
@@ -16,6 +16,7 @@
#include "ubsan_type_hash.h"
#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_ptrauth.h"
// The following are intended to be binary compatible with the definitions
// given in the Itanium ABI. We make no attempt to be ODR-compatible with
@@ -194,6 +195,7 @@ struct VtablePrefix {
std::type_info *TypeInfo;
};
VtablePrefix *getVtablePrefix(void *Vtable) {
+ Vtable = ptrauth_auth_data(Vtable, ptrauth_key_cxx_vtable_pointer, 0);
VtablePrefix *Vptr = reinterpret_cast<VtablePrefix*>(Vtable);
VtablePrefix *Prefix = Vptr - 1;
if (!IsAccessibleMemoryRange((uptr)Prefix, sizeof(VtablePrefix)))
--
2.26.2
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH] Libsanitizer: merge from master.
2020-06-02 6:00 [PATCH] Libsanitizer: " Martin Liška
@ 2020-06-06 19:47 ` Andreas Schwab
2020-10-16 8:59 ` Martin Liška
1 sibling, 0 replies; 17+ messages in thread
From: Andreas Schwab @ 2020-06-06 19:47 UTC (permalink / raw)
To: Martin Liška; +Cc: gcc-patches
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1880:12: warning: binary constants are a C++14 feature or GCC extension
1880 | case 0b10'010: // c.lwsp (rd != x0)
| ^~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1880:16: warning: missing terminating ' character
1880 | case 0b10'010: // c.lwsp (rd != x0)
| ^
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1880:16: error: missing terminating ' character
1880 | case 0b10'010: // c.lwsp (rd != x0)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1882:12: warning: binary constants are a C++14 feature or GCC extension
1882 | case 0b10'011: // c.ldsp (rd != x0)
| ^~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1882:16: warning: missing terminating ' character
1882 | case 0b10'011: // c.ldsp (rd != x0)
| ^
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1882:16: error: missing terminating ' character
1882 | case 0b10'011: // c.ldsp (rd != x0)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1885:12: warning: binary constants are a C++14 feature or GCC extension
1885 | case 0b00'010: // c.lw
| ^~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1885:16: warning: missing terminating ' character
1885 | case 0b00'010: // c.lw
| ^
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1885:16: error: missing terminating ' character
1885 | case 0b00'010: // c.lw
| ^~~~~~~~~~~~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1887:16: warning: missing terminating ' character
1887 | case 0b10'011: // c.flwsp
| ^
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1890:12: warning: binary constants are a C++14 feature or GCC extension
1890 | case 0b00'011: // c.flw / c.ld
| ^~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1890:16: warning: missing terminating ' character
1890 | case 0b00'011: // c.flw / c.ld
| ^
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1890:16: error: missing terminating ' character
1890 | case 0b00'011: // c.flw / c.ld
| ^~~~~~~~~~~~~~~~~~~~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1893:12: warning: binary constants are a C++14 feature or GCC extension
1893 | case 0b00'001: // c.fld
| ^~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1893:16: warning: missing terminating ' character
1893 | case 0b00'001: // c.fld
| ^
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1893:16: error: missing terminating ' character
1893 | case 0b00'001: // c.fld
| ^~~~~~~~~~~~~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1894:12: warning: binary constants are a C++14 feature or GCC extension
1894 | case 0b10'001: // c.fldsp
| ^~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1894:16: warning: missing terminating ' character
1894 | case 0b10'001: // c.fldsp
| ^
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1894:16: error: missing terminating ' character
1894 | case 0b10'001: // c.fldsp
| ^~~~~~~~~~~~~~~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1897:12: warning: binary constants are a C++14 feature or GCC extension
1897 | case 0b00'110: // c.sw
| ^~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1897:16: warning: missing terminating ' character
1897 | case 0b00'110: // c.sw
| ^
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1897:16: error: missing terminating ' character
1897 | case 0b00'110: // c.sw
| ^~~~~~~~~~~~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1898:12: warning: binary constants are a C++14 feature or GCC extension
1898 | case 0b10'110: // c.swsp
| ^~~~
| ^~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1898:16: warning: missing terminating ' character
1898 | case 0b10'110: // c.swsp
| ^
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1898:16: error: missing terminating ' character
1898 | case 0b10'110: // c.swsp
| ^~~~~~~~~~~~~~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1900:12: warning: binary constants are a C++14 feature or GCC extension
1900 | case 0b00'111: // c.fsw / c.sd
| ^~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1900:16: warning: missing terminating ' character
1900 | case 0b00'111: // c.fsw / c.sd
| ^
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1900:16: error: missing terminating ' character
1900 | case 0b00'111: // c.fsw / c.sd
| ^~~~~~~~~~~~~~~~~~~~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1901:12: warning: binary constants are a C++14 feature or GCC extension
1901 | case 0b10'111: // c.fswsp / c.sdsp
| ^~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1901:16: warning: missing terminating ' character
1901 | case 0b10'111: // c.fswsp / c.sdsp
| ^
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1901:16: error: missing terminating ' character
1901 | case 0b10'111: // c.fswsp / c.sdsp
| ^~~~~~~~~~~~~~~~~~~~~~~~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1904:12: warning: binary constants are a C++14 feature or GCC extension
1904 | case 0b00'101: // c.fsd
| ^~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1904:16: warning: missing terminating ' character
1904 | case 0b00'101: // c.fsd
| ^
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1904:16: error: missing terminating ' character
1904 | case 0b00'101: // c.fsd
| ^~~~~~~~~~~~~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1905:12: warning: binary constants are a C++14 feature or GCC extension
1905 | case 0b10'101: // c.fsdsp
| ^~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1905:16: warning: missing terminating ' character
1905 | case 0b10'101: // c.fsdsp
| ^
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1905:16: error: missing terminating ' character
1905 | case 0b10'101: // c.fsdsp
| ^~~~~~~~~~~~~~~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1917:10: warning: binary constants are a C++14 feature or GCC extension
1917 | case 0b0000011: // loads
| ^~~~~~~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1919:14: warning: binary constants are a C++14 feature or GCC extension
1919 | case 0b000: // lb
| ^~~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1920:14: warning: binary constants are a C++14 feature or GCC extension
1920 | case 0b001: // lh
| ^~~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1921:14: warning: binary constants are a C++14 feature or GCC extension
1921 | case 0b010: // lw
| ^~~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1923:14: warning: binary constants are a C++14 feature or GCC extension
1923 | case 0b011: // ld
| ^~~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1925:14: warning: binary constants are a C++14 feature or GCC extension
1925 | case 0b100: // lbu
| ^~~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1926:14: warning: binary constants are a C++14 feature or GCC extension
1926 | case 0b101: // lhu
| ^~~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1931:10: warning: binary constants are a C++14 feature or GCC extension
1931 | case 0b0100011: // stores
| ^~~~~~~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1933:14: warning: binary constants are a C++14 feature or GCC extension
1933 | case 0b000: // sb
| ^~~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1934:14: warning: binary constants are a C++14 feature or GCC extension
1934 | case 0b001: // sh
| ^~~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1935:14: warning: binary constants are a C++14 feature or GCC extension
1935 | case 0b010: // sw
| ^~~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1937:14: warning: binary constants are a C++14 feature or GCC extension
1937 | case 0b011: // sd
| ^~~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1944:10: warning: binary constants are a C++14 feature or GCC extension
1944 | case 0b0000111: // floating-point loads
| ^~~~~~~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1946:14: warning: binary constants are a C++14 feature or GCC extension
1946 | case 0b010: // flw
| ^~~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1948:14: warning: binary constants are a C++14 feature or GCC extension
1948 | case 0b011: // fld
| ^~~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1954:10: warning: binary constants are a C++14 feature or GCC extension
1954 | case 0b0100111: // floating-point stores
| ^~~~~~~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1956:14: warning: binary constants are a C++14 feature or GCC extension
1956 | case 0b010: // fsw
| ^~~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1958:14: warning: binary constants are a C++14 feature or GCC extension
1958 | case 0b011: // fsd
| ^~~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp: In member function '__sanitizer::SignalContext::WriteFlag __sanitizer::SignalContext::GetWriteFlag() const':
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1880:16: error: expected ':' before 'case'
1880 | case 0b10'010: // c.lwsp (rd != x0)
| ^
| :
1881 | #if __riscv_xlen == 64
1882 | case 0b10'011: // c.ldsp (rd != x0)
| ~~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1882:7: error: duplicate case value
1882 | case 0b10'011: // c.ldsp (rd != x0)
| ^~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1880:7: note: previously used here
1880 | case 0b10'010: // c.lwsp (rd != x0)
| ^~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1882:16: error: expected ':' before 'return'
1882 | case 0b10'011: // c.ldsp (rd != x0)
| ^
| :
1883 | #endif
1884 | return rd ? SignalContext::READ : SignalContext::UNKNOWN;
| ~~~~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1885:16: error: expected ':' before 'case'
1885 | case 0b00'010: // c.lw
| ^
| :
1890 | case 0b00'011: // c.flw / c.ld
| ~~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1890:7: error: duplicate case value
1890 | case 0b00'011: // c.flw / c.ld
| ^~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1885:7: note: previously used here
1885 | case 0b00'010: // c.lw
| ^~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1890:16: error: expected ':' before 'case'
1890 | case 0b00'011: // c.flw / c.ld
| ^
| :
1893 | case 0b00'001: // c.fld
| ~~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1893:7: error: duplicate case value
1893 | case 0b00'001: // c.fld
| ^~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1885:7: note: previously used here
1885 | case 0b00'010: // c.lw
| ^~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1893:16: error: expected ':' before 'case'
1893 | case 0b00'001: // c.fld
| ^
| :
1894 | case 0b10'001: // c.fldsp
| ~~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1894:7: error: duplicate case value
1894 | case 0b10'001: // c.fldsp
| ^~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1880:7: note: previously used here
1880 | case 0b10'010: // c.lwsp (rd != x0)
| ^~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1894:16: error: expected ':' before 'return'
1894 | case 0b10'001: // c.fldsp
| ^
| :
1895 | #endif
1896 | return SignalContext::READ;
| ~~~~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1897:7: error: duplicate case value
1897 | case 0b00'110: // c.sw
| ^~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1885:7: note: previously used here
1885 | case 0b00'010: // c.lw
| ^~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1897:16: error: expected ':' before 'case'
1897 | case 0b00'110: // c.sw
| ^
| :
1898 | case 0b10'110: // c.swsp
| ~~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1898:7: error: duplicate case value
1898 | case 0b10'110: // c.swsp
| ^~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1880:7: note: previously used here
1880 | case 0b10'010: // c.lwsp (rd != x0)
| ^~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1898:16: error: expected ':' before 'case'
1898 | case 0b10'110: // c.swsp
| ^
| :
1899 | #if __riscv_flen >= 32 || __riscv_xlen == 64
1900 | case 0b00'111: // c.fsw / c.sd
| ~~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1900:7: error: duplicate case value
1900 | case 0b00'111: // c.fsw / c.sd
| ^~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1885:7: note: previously used here
1885 | case 0b00'010: // c.lw
| ^~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1900:16: error: expected ':' before 'case'
1900 | case 0b00'111: // c.fsw / c.sd
| ^
| :
1901 | case 0b10'111: // c.fswsp / c.sdsp
| ~~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1901:7: error: duplicate case value
1901 | case 0b10'111: // c.fswsp / c.sdsp
| ^~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1880:7: note: previously used here
1880 | case 0b10'010: // c.lwsp (rd != x0)
| ^~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1901:16: error: expected ':' before 'case'
1901 | case 0b10'111: // c.fswsp / c.sdsp
| ^
| :
1904 | case 0b00'101: // c.fsd
| ~~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1904:7: error: duplicate case value
1904 | case 0b00'101: // c.fsd
| ^~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1885:7: note: previously used here
1885 | case 0b00'010: // c.lw
| ^~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1904:16: error: expected ':' before 'case'
1904 | case 0b00'101: // c.fsd
| ^
| :
1905 | case 0b10'101: // c.fsdsp
| ~~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1905:7: error: duplicate case value
1905 | case 0b10'101: // c.fsdsp
| ^~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1880:7: note: previously used here
1880 | case 0b10'010: // c.lwsp (rd != x0)
| ^~~~
../../../../libsanitizer/sanitizer_common/sanitizer_linux.cpp:1905:16: error: expected ':' before 'return'
1905 | case 0b10'101: // c.fsdsp
| ^
| :
1906 | #endif
1907 | return SignalContext::WRITE;
| ~~~~~~
make[4]: *** [Makefile:614: sanitizer_linux.lo] Error 1
make[4]: Leaving directory '/daten/riscv64/gcc/gcc-20200606/Build/riscv64-suse-linux/libsanitizer/sanitizer_common'
make[3]: *** [Makefile:528: all-recursive] Error 1
make[3]: Leaving directory '/daten/riscv64/gcc/gcc-20200606/Build/riscv64-suse-linux/libsanitizer'
make[2]: *** [Makefile:415: all] Error 2
make[2]: Leaving directory '/daten/riscv64/gcc/gcc-20200606/Build/riscv64-suse-linux/libsanitizer'
make[1]: *** [Makefile:17025: all-target-libsanitizer] Error 2
Andreas.
--
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 7578 EB47 D4E5 4D69 2510 2552 DF73 E780 A9DA AEC1
"And now for something completely different."
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH] Libsanitizer: merge from master.
2020-06-02 6:00 [PATCH] Libsanitizer: " Martin Liška
2020-06-06 19:47 ` Andreas Schwab
@ 2020-10-16 8:59 ` Martin Liška
2020-10-19 7:04 ` Tobias Burnus
1 sibling, 1 reply; 17+ messages in thread
From: Martin Liška @ 2020-10-16 8:59 UTC (permalink / raw)
To: gcc-patches
[-- Attachment #1: Type: text/plain, Size: 257073 bytes --]
On 6/2/20 8:00 AM, Martin Liška wrote:
> Merged from revision b638b63b99d66786cb37336292604a2ae3490cfd.
Hello.
I'm going to install one more merge from master.
>
> The patch successfully bootstraps on x86_64-linux-gnu and
> ppc64le-linux-gnu. I also tested ppc64-linux-gnu that exposed:
> https://reviews.llvm.org/D80864 (which is fixed on master).
Again I tested the patch on x86_64-linux-gnu and ppc64le-linux-gnu.
>
> Abidiff looks happy and I made UBSAN and ASAN bootstrap on
> x86_64-linux-gnu.
It's fine also now.
>
> I'm planning to do merge from master twice a year, once now and
> next time short before stage1 closes.
>
> I am going to install the patches as merge from master is obvious
> and I haven't made anything special.
>
> libsanitizer/ChangeLog:
>
> * MERGE: Merge from master.
> ---
> libsanitizer/MERGE | 2 +-
> libsanitizer/asan/asan_globals.cpp | 19 +
> libsanitizer/asan/asan_interceptors.h | 7 +-
> libsanitizer/asan/asan_mapping.h | 2 +-
> libsanitizer/asan/asan_report.cpp | 3 +
> libsanitizer/asan/asan_thread.cpp | 2 +
> .../include/sanitizer/linux_syscall_hooks.h | 8 +-
> .../include/sanitizer/netbsd_syscall_hooks.h | 2 +-
> .../include/sanitizer/tsan_interface.h | 20 +-
> libsanitizer/lsan/lsan.cpp | 17 +-
> libsanitizer/lsan/lsan.h | 6 +
> libsanitizer/lsan/lsan_allocator.h | 5 +-
> libsanitizer/lsan/lsan_common.cpp | 51 +-
> libsanitizer/lsan/lsan_common.h | 17 +-
> libsanitizer/lsan/lsan_common_fuchsia.cpp | 166 +++++
> libsanitizer/lsan/lsan_common_linux.cpp | 3 +-
> libsanitizer/lsan/lsan_common_mac.cpp | 3 +-
> libsanitizer/lsan/lsan_fuchsia.cpp | 123 ++++
> libsanitizer/lsan/lsan_fuchsia.h | 35 +
> libsanitizer/lsan/lsan_interceptors.cpp | 19 +-
> libsanitizer/lsan/lsan_linux.cpp | 6 +-
> libsanitizer/lsan/lsan_posix.cpp | 96 +++
> libsanitizer/lsan/lsan_posix.h | 49 ++
> libsanitizer/lsan/lsan_thread.cpp | 98 +--
> libsanitizer/lsan/lsan_thread.h | 35 +-
> .../sanitizer_common/sanitizer_allocator.cpp | 4 +-
> .../sanitizer_allocator_primary64.h | 10 +-
> .../sanitizer_common/sanitizer_common.cpp | 2 +
> .../sanitizer_common/sanitizer_common.h | 5 +-
> .../sanitizer_common_interceptors.inc | 190 +++++-
> ...izer_common_interceptors_netbsd_compat.inc | 128 ++++
> .../sanitizer_common_libcdep.cpp | 12 +-
> .../sanitizer_common_syscalls.inc | 17 +
> .../sanitizer_coverage_fuchsia.cpp | 25 +-
> .../sanitizer_coverage_interface.inc | 1 +
> .../sanitizer_coverage_libcdep_new.cpp | 1 +
> .../sanitizer_common/sanitizer_file.h | 4 +-
> .../sanitizer_flag_parser.cpp | 11 +-
> .../sanitizer_common/sanitizer_flag_parser.h | 49 ++
> .../sanitizer_common/sanitizer_flags.cpp | 10 +-
> .../sanitizer_common/sanitizer_freebsd.h | 23 +-
> .../sanitizer_common/sanitizer_fuchsia.cpp | 4 +
> .../sanitizer_common/sanitizer_fuchsia.h | 6 +
> .../sanitizer_interceptors_ioctl_netbsd.inc | 18 +-
> .../sanitizer_interface_internal.h | 6 +-
> .../sanitizer_internal_defs.h | 2 +-
> .../sanitizer_common/sanitizer_libc.h | 2 +
> .../sanitizer_common/sanitizer_linux.cpp | 151 ++++-
> .../sanitizer_common/sanitizer_linux.h | 2 +
> .../sanitizer_linux_libcdep.cpp | 17 +-
> .../sanitizer_common/sanitizer_linux_s390.cpp | 11 +-
> .../sanitizer_common/sanitizer_mac.cpp | 81 ++-
> libsanitizer/sanitizer_common/sanitizer_mac.h | 21 +-
> .../sanitizer_common/sanitizer_malloc_mac.inc | 18 +-
> .../sanitizer_common/sanitizer_netbsd.cpp | 7 +-
> .../sanitizer_platform_interceptors.h | 24 +
> .../sanitizer_platform_limits_freebsd.cpp | 614 +++++++++---------
> .../sanitizer_platform_limits_freebsd.h | 32 +-
> .../sanitizer_platform_limits_linux.cpp | 7 +-
> .../sanitizer_platform_limits_netbsd.cpp | 191 ++++++
> .../sanitizer_platform_limits_netbsd.h | 33 +-
> .../sanitizer_platform_limits_openbsd.cpp | 1 +
> .../sanitizer_platform_limits_openbsd.h | 1 +
> .../sanitizer_platform_limits_posix.cpp | 1 +
> .../sanitizer_platform_limits_posix.h | 3 +-
> .../sanitizer_platform_limits_solaris.cpp | 1 +
> .../sanitizer_platform_limits_solaris.h | 1 +
> .../sanitizer_common/sanitizer_posix.cpp | 10 +-
> .../sanitizer_common/sanitizer_posix.h | 4 +-
> .../sanitizer_posix_libcdep.cpp | 6 +-
> .../sanitizer_common/sanitizer_procmaps.h | 7 +-
> .../sanitizer_procmaps_fuchsia.cpp | 80 +++
> .../sanitizer_common/sanitizer_ptrauth.h | 21 +
> .../sanitizer_common/sanitizer_rtems.cpp | 4 +
> .../sanitizer_common/sanitizer_stacktrace.cpp | 17 +-
> .../sanitizer_stoptheworld_fuchsia.cpp | 42 ++
> .../sanitizer_stoptheworld_mac.cpp | 9 +-
> .../sanitizer_stoptheworld_netbsd_libcdep.cpp | 12 +-
> .../sanitizer_common/sanitizer_symbolizer.cpp | 6 +
> .../sanitizer_common/sanitizer_symbolizer.h | 3 +
> .../sanitizer_symbolizer_internal.h | 7 +
> .../sanitizer_symbolizer_libcdep.cpp | 89 ++-
> .../sanitizer_symbolizer_mac.cpp | 88 ++-
> .../sanitizer_symbolizer_mac.h | 1 +
> .../sanitizer_symbolizer_markup.cpp | 4 +-
> .../sanitizer_symbolizer_posix_libcdep.cpp | 16 +-
> .../sanitizer_symbolizer_win.cpp | 2 +-
> .../sanitizer_syscalls_netbsd.inc | 22 +-
> .../sanitizer_common/sanitizer_win.cpp | 9 +-
> libsanitizer/tsan/tsan_clock.cpp | 68 +-
> libsanitizer/tsan/tsan_clock.h | 58 ++
> libsanitizer/tsan/tsan_interceptors_posix.cpp | 21 +-
> libsanitizer/tsan/tsan_platform.h | 1 +
> libsanitizer/tsan/tsan_platform_mac.cpp | 10 +-
> libsanitizer/tsan/tsan_rtl.cpp | 12 +-
> libsanitizer/tsan/tsan_rtl.h | 4 +-
> libsanitizer/tsan/tsan_rtl_mutex.cpp | 25 +-
> libsanitizer/tsan/tsan_rtl_ppc64.S | 1 -
> libsanitizer/tsan/tsan_rtl_thread.cpp | 34 +-
> libsanitizer/tsan/tsan_stat.h | 1 +
> libsanitizer/ubsan/ubsan_checks.inc | 6 +
> libsanitizer/ubsan/ubsan_flags.cpp | 1 -
> libsanitizer/ubsan/ubsan_handlers.cpp | 65 +-
> libsanitizer/ubsan/ubsan_handlers.h | 8 -
> libsanitizer/ubsan/ubsan_init.cpp | 2 +
> libsanitizer/ubsan/ubsan_platform.h | 2 -
> .../ubsan/ubsan_type_hash_itanium.cpp | 2 +
> 107 files changed, 2551 insertions(+), 770 deletions(-)
> create mode 100644 libsanitizer/lsan/lsan_common_fuchsia.cpp
> create mode 100644 libsanitizer/lsan/lsan_fuchsia.cpp
> create mode 100644 libsanitizer/lsan/lsan_fuchsia.h
> create mode 100644 libsanitizer/lsan/lsan_posix.cpp
> create mode 100644 libsanitizer/lsan/lsan_posix.h
> create mode 100644 libsanitizer/sanitizer_common/sanitizer_common_interceptors_netbsd_compat.inc
> create mode 100644 libsanitizer/sanitizer_common/sanitizer_procmaps_fuchsia.cpp
> create mode 100644 libsanitizer/sanitizer_common/sanitizer_ptrauth.h
> create mode 100644 libsanitizer/sanitizer_common/sanitizer_stoptheworld_fuchsia.cpp
>
> diff --git a/libsanitizer/MERGE b/libsanitizer/MERGE
> index 49ee2c3bab8..e14e830ea7d 100644
> --- a/libsanitizer/MERGE
> +++ b/libsanitizer/MERGE
> @@ -1,4 +1,4 @@
> -82588e05cc32bb30807e480abd4e689b0dee132a
> +b638b63b99d66786cb37336292604a2ae3490cfd
>
> The first line of this file holds the git revision number of the
> last merge done from the master library sources.
> diff --git a/libsanitizer/asan/asan_globals.cpp b/libsanitizer/asan/asan_globals.cpp
> index e045c31cd1c..9d7dbc6f264 100644
> --- a/libsanitizer/asan/asan_globals.cpp
> +++ b/libsanitizer/asan/asan_globals.cpp
> @@ -154,6 +154,23 @@ static void CheckODRViolationViaIndicator(const Global *g) {
> }
> }
>
> +// Check ODR violation for given global G by checking if it's already poisoned.
> +// We use this method in case compiler doesn't use private aliases for global
> +// variables.
> +static void CheckODRViolationViaPoisoning(const Global *g) {
> + if (__asan_region_is_poisoned(g->beg, g->size_with_redzone)) {
> + // This check may not be enough: if the first global is much larger
> + // the entire redzone of the second global may be within the first global.
> + for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) {
> + if (g->beg == l->g->beg &&
> + (flags()->detect_odr_violation >= 2 || g->size != l->g->size) &&
> + !IsODRViolationSuppressed(g->name))
> + ReportODRViolation(g, FindRegistrationSite(g),
> + l->g, FindRegistrationSite(l->g));
> + }
> + }
> +}
> +
> // Clang provides two different ways for global variables protection:
> // it can poison the global itself or its private alias. In former
> // case we may poison same symbol multiple times, that can help us to
> @@ -199,6 +216,8 @@ static void RegisterGlobal(const Global *g) {
> // where two globals with the same name are defined in different modules.
> if (UseODRIndicator(g))
> CheckODRViolationViaIndicator(g);
> + else
> + CheckODRViolationViaPoisoning(g);
> }
> if (CanPoisonMemory())
> PoisonRedZones(*g);
> diff --git a/libsanitizer/asan/asan_interceptors.h b/libsanitizer/asan/asan_interceptors.h
> index b7a85fedbdf..344a64bd83d 100644
> --- a/libsanitizer/asan/asan_interceptors.h
> +++ b/libsanitizer/asan/asan_interceptors.h
> @@ -80,12 +80,7 @@ void InitializePlatformInterceptors();
> #if ASAN_HAS_EXCEPTIONS && !SANITIZER_WINDOWS && !SANITIZER_SOLARIS && \
> !SANITIZER_NETBSD
> # define ASAN_INTERCEPT___CXA_THROW 1
> -# if ! defined(ASAN_HAS_CXA_RETHROW_PRIMARY_EXCEPTION) \
> - || ASAN_HAS_CXA_RETHROW_PRIMARY_EXCEPTION
> -# define ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION 1
> -# else
> -# define ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION 0
> -# endif
> +# define ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION 1
> # if defined(_GLIBCXX_SJLJ_EXCEPTIONS) || (SANITIZER_IOS && defined(__arm__))
> # define ASAN_INTERCEPT__UNWIND_SJLJ_RAISEEXCEPTION 1
> # else
> diff --git a/libsanitizer/asan/asan_mapping.h b/libsanitizer/asan/asan_mapping.h
> index 09be904270c..41fb49ee46d 100644
> --- a/libsanitizer/asan/asan_mapping.h
> +++ b/libsanitizer/asan/asan_mapping.h
> @@ -163,7 +163,7 @@ static const u64 kDefaultShort64bitShadowOffset =
> static const u64 kAArch64_ShadowOffset64 = 1ULL << 36;
> static const u64 kMIPS32_ShadowOffset32 = 0x0aaa0000;
> static const u64 kMIPS64_ShadowOffset64 = 1ULL << 37;
> -static const u64 kPPC64_ShadowOffset64 = 1ULL << 41;
> +static const u64 kPPC64_ShadowOffset64 = 1ULL << 44;
> static const u64 kSystemZ_ShadowOffset64 = 1ULL << 52;
> static const u64 kSPARC64_ShadowOffset64 = 1ULL << 43; // 0x80000000000
> static const u64 kFreeBSD_ShadowOffset32 = 1ULL << 30; // 0x40000000
> diff --git a/libsanitizer/asan/asan_report.cpp b/libsanitizer/asan/asan_report.cpp
> index 2e6ce436d03..99e8678aa78 100644
> --- a/libsanitizer/asan/asan_report.cpp
> +++ b/libsanitizer/asan/asan_report.cpp
> @@ -160,6 +160,9 @@ class ScopedInErrorReport {
> BlockingMutexLock l(&error_message_buf_mutex);
> internal_memcpy(buffer_copy.data(),
> error_message_buffer, kErrorMessageBufferSize);
> + // Clear error_message_buffer so that if we find other errors
> + // we don't re-log this error.
> + error_message_buffer_pos = 0;
> }
>
> LogFullErrorReport(buffer_copy.data());
> diff --git a/libsanitizer/asan/asan_thread.cpp b/libsanitizer/asan/asan_thread.cpp
> index 6734d9a1668..f0df8bd4b37 100644
> --- a/libsanitizer/asan/asan_thread.cpp
> +++ b/libsanitizer/asan/asan_thread.cpp
> @@ -480,6 +480,8 @@ bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end,
> return true;
> }
>
> +void GetAllThreadAllocatorCachesLocked(InternalMmapVector<uptr> *caches) {}
> +
> void ForEachExtraStackRange(tid_t os_id, RangeIteratorCallback callback,
> void *arg) {
> __asan::AsanThread *t = __asan::GetAsanThreadByOsIDLocked(os_id);
> diff --git a/libsanitizer/include/sanitizer/linux_syscall_hooks.h b/libsanitizer/include/sanitizer/linux_syscall_hooks.h
> index a1794b71af5..56eae3d40f9 100644
> --- a/libsanitizer/include/sanitizer/linux_syscall_hooks.h
> +++ b/libsanitizer/include/sanitizer/linux_syscall_hooks.h
> @@ -1845,6 +1845,10 @@
> #define __sanitizer_syscall_post_rt_sigaction(res, signum, act, oldact, sz) \
> __sanitizer_syscall_post_impl_rt_sigaction(res, (long)signum, (long)act, \
> (long)oldact, (long)sz)
> +#define __sanitizer_syscall_pre_sigaltstack(ss, oss) \
> + __sanitizer_syscall_pre_impl_sigaltstack((long)ss, (long)oss)
> +#define __sanitizer_syscall_post_sigaltstack(res, ss, oss) \
> + __sanitizer_syscall_post_impl_sigaltstack(res, (long)ss, (long)oss)
>
> // And now a few syscalls we don't handle yet.
> #define __sanitizer_syscall_pre_afs_syscall(...)
> @@ -1912,7 +1916,6 @@
> #define __sanitizer_syscall_pre_setreuid32(...)
> #define __sanitizer_syscall_pre_set_thread_area(...)
> #define __sanitizer_syscall_pre_setuid32(...)
> -#define __sanitizer_syscall_pre_sigaltstack(...)
> #define __sanitizer_syscall_pre_sigreturn(...)
> #define __sanitizer_syscall_pre_sigsuspend(...)
> #define __sanitizer_syscall_pre_stty(...)
> @@ -1992,7 +1995,6 @@
> #define __sanitizer_syscall_post_setreuid32(res, ...)
> #define __sanitizer_syscall_post_set_thread_area(res, ...)
> #define __sanitizer_syscall_post_setuid32(res, ...)
> -#define __sanitizer_syscall_post_sigaltstack(res, ...)
> #define __sanitizer_syscall_post_sigreturn(res, ...)
> #define __sanitizer_syscall_post_sigsuspend(res, ...)
> #define __sanitizer_syscall_post_stty(res, ...)
> @@ -3075,6 +3077,8 @@ void __sanitizer_syscall_pre_impl_rt_sigaction(long signum, long act,
> long oldact, long sz);
> void __sanitizer_syscall_post_impl_rt_sigaction(long res, long signum, long act,
> long oldact, long sz);
> +void __sanitizer_syscall_pre_impl_sigaltstack(long ss, long oss);
> +void __sanitizer_syscall_post_impl_sigaltstack(long res, long ss, long oss);
> #ifdef __cplusplus
> } // extern "C"
> #endif
> diff --git a/libsanitizer/include/sanitizer/netbsd_syscall_hooks.h b/libsanitizer/include/sanitizer/netbsd_syscall_hooks.h
> index 174b4bf06de..370da0ea72e 100644
> --- a/libsanitizer/include/sanitizer/netbsd_syscall_hooks.h
> +++ b/libsanitizer/include/sanitizer/netbsd_syscall_hooks.h
> @@ -20,7 +20,7 @@
> // DO NOT EDIT! THIS FILE HAS BEEN GENERATED!
> //
> // Generated with: generate_netbsd_syscalls.awk
> -// Generated date: 2019-11-01
> +// Generated date: 2019-12-24
> // Generated from: syscalls.master,v 1.296 2019/09/22 22:59:39 christos Exp
> //
> //===----------------------------------------------------------------------===//
> diff --git a/libsanitizer/include/sanitizer/tsan_interface.h b/libsanitizer/include/sanitizer/tsan_interface.h
> index 011b23350ca..96b8ad58541 100644
> --- a/libsanitizer/include/sanitizer/tsan_interface.h
> +++ b/libsanitizer/include/sanitizer/tsan_interface.h
> @@ -38,34 +38,34 @@ void __tsan_release(void *addr);
>
> // Mutex has static storage duration and no-op constructor and destructor.
> // This effectively makes tsan ignore destroy annotation.
> -const unsigned __tsan_mutex_linker_init = 1 << 0;
> +static const unsigned __tsan_mutex_linker_init = 1 << 0;
> // Mutex is write reentrant.
> -const unsigned __tsan_mutex_write_reentrant = 1 << 1;
> +static const unsigned __tsan_mutex_write_reentrant = 1 << 1;
> // Mutex is read reentrant.
> -const unsigned __tsan_mutex_read_reentrant = 1 << 2;
> +static const unsigned __tsan_mutex_read_reentrant = 1 << 2;
> // Mutex does not have static storage duration, and must not be used after
> // its destructor runs. The opposite of __tsan_mutex_linker_init.
> // If this flag is passed to __tsan_mutex_destroy, then the destruction
> // is ignored unless this flag was previously set on the mutex.
> -const unsigned __tsan_mutex_not_static = 1 << 8;
> +static const unsigned __tsan_mutex_not_static = 1 << 8;
>
> // Mutex operation flags:
>
> // Denotes read lock operation.
> -const unsigned __tsan_mutex_read_lock = 1 << 3;
> +static const unsigned __tsan_mutex_read_lock = 1 << 3;
> // Denotes try lock operation.
> -const unsigned __tsan_mutex_try_lock = 1 << 4;
> +static const unsigned __tsan_mutex_try_lock = 1 << 4;
> // Denotes that a try lock operation has failed to acquire the mutex.
> -const unsigned __tsan_mutex_try_lock_failed = 1 << 5;
> +static const unsigned __tsan_mutex_try_lock_failed = 1 << 5;
> // Denotes that the lock operation acquires multiple recursion levels.
> // Number of levels is passed in recursion parameter.
> // This is useful for annotation of e.g. Java builtin monitors,
> // for which wait operation releases all recursive acquisitions of the mutex.
> -const unsigned __tsan_mutex_recursive_lock = 1 << 6;
> +static const unsigned __tsan_mutex_recursive_lock = 1 << 6;
> // Denotes that the unlock operation releases all recursion levels.
> // Number of released levels is returned and later must be passed to
> // the corresponding __tsan_mutex_post_lock annotation.
> -const unsigned __tsan_mutex_recursive_unlock = 1 << 7;
> +static const unsigned __tsan_mutex_recursive_unlock = 1 << 7;
>
> // Annotate creation of a mutex.
> // Supported flags: mutex creation flags.
> @@ -152,7 +152,7 @@ void __tsan_set_fiber_name(void *fiber, const char *name);
>
> // Flags for __tsan_switch_to_fiber:
> // Do not establish a happens-before relation between fibers
> -const unsigned __tsan_switch_to_fiber_no_sync = 1 << 0;
> +static const unsigned __tsan_switch_to_fiber_no_sync = 1 << 0;
>
> #ifdef __cplusplus
> } // extern "C"
> diff --git a/libsanitizer/lsan/lsan.cpp b/libsanitizer/lsan/lsan.cpp
> index 4ce03046ffb..80a6e2fa701 100644
> --- a/libsanitizer/lsan/lsan.cpp
> +++ b/libsanitizer/lsan/lsan.cpp
> @@ -15,7 +15,6 @@
>
> #include "sanitizer_common/sanitizer_flags.h"
> #include "sanitizer_common/sanitizer_flag_parser.h"
> -#include "sanitizer_common/sanitizer_stacktrace.h"
> #include "lsan_allocator.h"
> #include "lsan_common.h"
> #include "lsan_thread.h"
> @@ -87,17 +86,6 @@ static void InitializeFlags() {
> __sanitizer_set_report_path(common_flags()->log_path);
> }
>
> -static void OnStackUnwind(const SignalContext &sig, const void *,
> - BufferedStackTrace *stack) {
> - stack->Unwind(StackTrace::GetNextInstructionPc(sig.pc), sig.bp, sig.context,
> - common_flags()->fast_unwind_on_fatal);
> -}
> -
> -static void LsanOnDeadlySignal(int signo, void *siginfo, void *context) {
> - HandleDeadlySignal(siginfo, context, GetCurrentThread(), &OnStackUnwind,
> - nullptr);
> -}
> -
> extern "C" void __lsan_init() {
> CHECK(!lsan_init_is_running);
> if (lsan_inited)
> @@ -114,10 +102,7 @@ extern "C" void __lsan_init() {
> InitializeInterceptors();
> InitializeThreadRegistry();
> InstallDeadlySignalHandlers(LsanOnDeadlySignal);
> - u32 tid = ThreadCreate(0, 0, true);
> - CHECK_EQ(tid, 0);
> - ThreadStart(tid, GetTid());
> - SetCurrentThread(tid);
> + InitializeMainThread();
>
> if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit)
> Atexit(DoLeakCheck);
> diff --git a/libsanitizer/lsan/lsan.h b/libsanitizer/lsan/lsan.h
> index 9904ada4bb3..1e82ad72f00 100644
> --- a/libsanitizer/lsan/lsan.h
> +++ b/libsanitizer/lsan/lsan.h
> @@ -12,6 +12,11 @@
> //===----------------------------------------------------------------------===//
>
> #include "lsan_thread.h"
> +#if SANITIZER_POSIX
> +#include "lsan_posix.h"
> +#elif SANITIZER_FUCHSIA
> +#include "lsan_fuchsia.h"
> +#endif
> #include "sanitizer_common/sanitizer_flags.h"
> #include "sanitizer_common/sanitizer_stacktrace.h"
>
> @@ -33,6 +38,7 @@ namespace __lsan {
>
> void InitializeInterceptors();
> void ReplaceSystemMalloc();
> +void LsanOnDeadlySignal(int signo, void *siginfo, void *context);
>
> #define ENSURE_LSAN_INITED do { \
> CHECK(!lsan_init_is_running); \
> diff --git a/libsanitizer/lsan/lsan_allocator.h b/libsanitizer/lsan/lsan_allocator.h
> index e1397099767..bda9d8cdf74 100644
> --- a/libsanitizer/lsan/lsan_allocator.h
> +++ b/libsanitizer/lsan/lsan_allocator.h
> @@ -66,7 +66,10 @@ template <typename AddressSpaceView>
> using PrimaryAllocatorASVT = SizeClassAllocator32<AP32<AddressSpaceView>>;
> using PrimaryAllocator = PrimaryAllocatorASVT<LocalAddressSpaceView>;
> #elif defined(__x86_64__) || defined(__powerpc64__)
> -# if defined(__powerpc64__)
> +# if SANITIZER_FUCHSIA
> +const uptr kAllocatorSpace = ~(uptr)0;
> +const uptr kAllocatorSize = 0x40000000000ULL; // 4T.
> +# elif defined(__powerpc64__)
> const uptr kAllocatorSpace = 0xa0000000000ULL;
> const uptr kAllocatorSize = 0x20000000000ULL; // 2T.
> # else
> diff --git a/libsanitizer/lsan/lsan_common.cpp b/libsanitizer/lsan/lsan_common.cpp
> index 9ff9f4c5d1c..32ea4e88003 100644
> --- a/libsanitizer/lsan/lsan_common.cpp
> +++ b/libsanitizer/lsan/lsan_common.cpp
> @@ -211,6 +211,13 @@ void ForEachExtraStackRangeCb(uptr begin, uptr end, void* arg) {
> ScanRangeForPointers(begin, end, frontier, "FAKE STACK", kReachable);
> }
>
> +#if SANITIZER_FUCHSIA
> +
> +// Fuchsia handles all threads together with its own callback.
> +static void ProcessThreads(SuspendedThreadsList const &, Frontier *) {}
> +
> +#else
> +
> // Scans thread data (stacks and TLS) for heap pointers.
> static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
> Frontier *frontier) {
> @@ -308,6 +315,8 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
> }
> }
>
> +#endif // SANITIZER_FUCHSIA
> +
> void ScanRootRegion(Frontier *frontier, const RootRegion &root_region,
> uptr region_begin, uptr region_end, bool is_readable) {
> uptr intersection_begin = Max(root_region.begin, region_begin);
> @@ -443,25 +452,23 @@ void ProcessPC(Frontier *frontier) {
> }
>
> // Sets the appropriate tag on each chunk.
> -static void ClassifyAllChunks(SuspendedThreadsList const &suspended_threads) {
> - // Holds the flood fill frontier.
> - Frontier frontier;
> -
> - ForEachChunk(CollectIgnoredCb, &frontier);
> - ProcessGlobalRegions(&frontier);
> - ProcessThreads(suspended_threads, &frontier);
> - ProcessRootRegions(&frontier);
> - FloodFillTag(&frontier, kReachable);
> +static void ClassifyAllChunks(SuspendedThreadsList const &suspended_threads,
> + Frontier *frontier) {
> + ForEachChunk(CollectIgnoredCb, frontier);
> + ProcessGlobalRegions(frontier);
> + ProcessThreads(suspended_threads, frontier);
> + ProcessRootRegions(frontier);
> + FloodFillTag(frontier, kReachable);
>
> - CHECK_EQ(0, frontier.size());
> - ProcessPC(&frontier);
> + CHECK_EQ(0, frontier->size());
> + ProcessPC(frontier);
>
> // 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.
> LOG_POINTERS("Processing platform-specific allocations.\n");
> - ProcessPlatformSpecificAllocations(&frontier);
> - FloodFillTag(&frontier, kReachable);
> + ProcessPlatformSpecificAllocations(frontier);
> + FloodFillTag(frontier, kReachable);
>
> // Iterate over leaked chunks and mark those that are reachable from other
> // leaked chunks.
> @@ -521,11 +528,6 @@ static void PrintMatchedSuppressions() {
> Printf("%s\n\n", line);
> }
>
> -struct CheckForLeaksParam {
> - bool success;
> - LeakReport leak_report;
> -};
> -
> static void ReportIfNotSuspended(ThreadContextBase *tctx, void *arg) {
> const InternalMmapVector<tid_t> &suspended_threads =
> *(const InternalMmapVector<tid_t> *)arg;
> @@ -538,6 +540,14 @@ static void ReportIfNotSuspended(ThreadContextBase *tctx, void *arg) {
> }
> }
>
> +#if SANITIZER_FUCHSIA
> +
> +// Fuchsia provides a libc interface that guarantees all threads are
> +// covered, and SuspendedThreadList is never really used.
> +static void ReportUnsuspendedThreads(const SuspendedThreadsList &) {}
> +
> +#else // !SANITIZER_FUCHSIA
> +
> static void ReportUnsuspendedThreads(
> const SuspendedThreadsList &suspended_threads) {
> InternalMmapVector<tid_t> threads(suspended_threads.ThreadCount());
> @@ -550,13 +560,15 @@ static void ReportUnsuspendedThreads(
> &ReportIfNotSuspended, &threads);
> }
>
> +#endif // !SANITIZER_FUCHSIA
> +
> static void CheckForLeaksCallback(const SuspendedThreadsList &suspended_threads,
> void *arg) {
> CheckForLeaksParam *param = reinterpret_cast<CheckForLeaksParam *>(arg);
> CHECK(param);
> CHECK(!param->success);
> ReportUnsuspendedThreads(suspended_threads);
> - ClassifyAllChunks(suspended_threads);
> + ClassifyAllChunks(suspended_threads, ¶m->frontier);
> ForEachChunk(CollectLeaksCb, ¶m->leak_report);
> // Clean up for subsequent leak checks. This assumes we did not overwrite any
> // kIgnored tags.
> @@ -569,7 +581,6 @@ static bool CheckForLeaks() {
> return false;
> EnsureMainThreadIDIsCorrect();
> CheckForLeaksParam param;
> - param.success = false;
> LockStuffAndStopTheWorld(CheckForLeaksCallback, ¶m);
>
> if (!param.success) {
> diff --git a/libsanitizer/lsan/lsan_common.h b/libsanitizer/lsan/lsan_common.h
> index d24abe31b71..6252d52c197 100644
> --- a/libsanitizer/lsan/lsan_common.h
> +++ b/libsanitizer/lsan/lsan_common.h
> @@ -40,7 +40,7 @@
> #elif defined(__arm__) && \
> SANITIZER_LINUX && !SANITIZER_ANDROID
> #define CAN_SANITIZE_LEAKS 1
> -#elif SANITIZER_NETBSD
> +#elif SANITIZER_NETBSD || SANITIZER_FUCHSIA
> #define CAN_SANITIZE_LEAKS 1
> #else
> #define CAN_SANITIZE_LEAKS 0
> @@ -126,12 +126,24 @@ struct RootRegion {
> uptr size;
> };
>
> +// LockStuffAndStopTheWorld can start to use Scan* calls to collect into
> +// this Frontier vector before the StopTheWorldCallback actually runs.
> +// This is used when the OS has a unified callback API for suspending
> +// threads and enumerating roots.
> +struct CheckForLeaksParam {
> + Frontier frontier;
> + LeakReport leak_report;
> + bool success = false;
> +};
> +
> InternalMmapVector<RootRegion> const *GetRootRegions();
> void ScanRootRegion(Frontier *frontier, RootRegion const ®ion,
> uptr region_begin, uptr region_end, bool is_readable);
> +void ForEachExtraStackRangeCb(uptr begin, uptr end, void* arg);
> // Run stoptheworld while holding any platform-specific locks, as well as the
> // allocator and thread registry locks.
> -void LockStuffAndStopTheWorld(StopTheWorldCallback callback, void* argument);
> +void LockStuffAndStopTheWorld(StopTheWorldCallback callback,
> + CheckForLeaksParam* argument);
>
> void ScanRangeForPointers(uptr begin, uptr end,
> Frontier *frontier,
> @@ -211,6 +223,7 @@ ThreadRegistry *GetThreadRegistryLocked();
> bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end,
> uptr *tls_begin, uptr *tls_end, uptr *cache_begin,
> uptr *cache_end, DTLS **dtls);
> +void GetAllThreadAllocatorCachesLocked(InternalMmapVector<uptr> *caches);
> void ForEachExtraStackRange(tid_t os_id, RangeIteratorCallback callback,
> void *arg);
> // If called from the main thread, updates the main thread's TID in the thread
> diff --git a/libsanitizer/lsan/lsan_common_fuchsia.cpp b/libsanitizer/lsan/lsan_common_fuchsia.cpp
> new file mode 100644
> index 00000000000..caedbf15596
> --- /dev/null
> +++ b/libsanitizer/lsan/lsan_common_fuchsia.cpp
> @@ -0,0 +1,166 @@
> +//=-- lsan_common_fuchsia.cpp --------------------------------------------===//
> +//
> +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
> +// See https://llvm.org/LICENSE.txt for license information.
> +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
> +//
> +//===---------------------------------------------------------------------===//
> +//
> +// This file is a part of LeakSanitizer.
> +// Implementation of common leak checking functionality. Fuchsia-specific code.
> +//
> +//===---------------------------------------------------------------------===//
> +
> +#include "lsan_common.h"
> +#include "sanitizer_common/sanitizer_platform.h"
> +
> +#if CAN_SANITIZE_LEAKS && SANITIZER_FUCHSIA
> +#include <zircon/sanitizer.h>
> +
> +#include "lsan_allocator.h"
> +#include "sanitizer_common/sanitizer_flags.h"
> +#include "sanitizer_common/sanitizer_thread_registry.h"
> +
> +// Ensure that the Zircon system ABI is linked in.
> +#pragma comment(lib, "zircon")
> +
> +namespace __lsan {
> +
> +void InitializePlatformSpecificModules() {}
> +
> +LoadedModule *GetLinker() { return nullptr; }
> +
> +__attribute__((tls_model("initial-exec"))) THREADLOCAL int disable_counter;
> +bool DisabledInThisThread() { return disable_counter > 0; }
> +void DisableInThisThread() { disable_counter++; }
> +void EnableInThisThread() {
> + if (disable_counter == 0) {
> + DisableCounterUnderflow();
> + }
> + disable_counter--;
> +}
> +
> +// There is nothing left to do after the globals callbacks.
> +void ProcessGlobalRegions(Frontier *frontier) {}
> +
> +// Nothing to do here.
> +void ProcessPlatformSpecificAllocations(Frontier *frontier) {}
> +
> +// On Fuchsia, we can intercept _Exit gracefully, and return a failing exit
> +// code if required at that point. Calling Die() here is undefined
> +// behavior and causes rare race conditions.
> +void HandleLeaks() {}
> +
> +int ExitHook(int status) {
> + return status == 0 && HasReportedLeaks() ? common_flags()->exitcode : status;
> +}
> +
> +void LockStuffAndStopTheWorld(StopTheWorldCallback callback,
> + CheckForLeaksParam *argument) {
> + LockThreadRegistry();
> + LockAllocator();
> +
> + struct Params {
> + InternalMmapVector<uptr> allocator_caches;
> + StopTheWorldCallback callback;
> + CheckForLeaksParam *argument;
> + } params = {{}, callback, argument};
> +
> + // Callback from libc for globals (data/bss modulo relro), when enabled.
> + auto globals = +[](void *chunk, size_t size, void *data) {
> + auto params = static_cast<const Params *>(data);
> + uptr begin = reinterpret_cast<uptr>(chunk);
> + uptr end = begin + size;
> + ScanGlobalRange(begin, end, ¶ms->argument->frontier);
> + };
> +
> + // Callback from libc for thread stacks.
> + auto stacks = +[](void *chunk, size_t size, void *data) {
> + auto params = static_cast<const Params *>(data);
> + uptr begin = reinterpret_cast<uptr>(chunk);
> + uptr end = begin + size;
> + ScanRangeForPointers(begin, end, ¶ms->argument->frontier, "STACK",
> + kReachable);
> + };
> +
> + // Callback from libc for thread registers.
> + auto registers = +[](void *chunk, size_t size, void *data) {
> + auto params = static_cast<const Params *>(data);
> + uptr begin = reinterpret_cast<uptr>(chunk);
> + uptr end = begin + size;
> + ScanRangeForPointers(begin, end, ¶ms->argument->frontier, "REGISTERS",
> + kReachable);
> + };
> +
> + if (flags()->use_tls) {
> + // Collect the allocator cache range from each thread so these
> + // can all be excluded from the reported TLS ranges.
> + GetAllThreadAllocatorCachesLocked(¶ms.allocator_caches);
> + __sanitizer::Sort(params.allocator_caches.data(),
> + params.allocator_caches.size());
> + }
> +
> + // Callback from libc for TLS regions. This includes thread_local
> + // variables as well as C11 tss_set and POSIX pthread_setspecific.
> + auto tls = +[](void *chunk, size_t size, void *data) {
> + auto params = static_cast<const Params *>(data);
> + uptr begin = reinterpret_cast<uptr>(chunk);
> + uptr end = begin + size;
> + auto i = __sanitizer::InternalLowerBound(params->allocator_caches, 0,
> + params->allocator_caches.size(),
> + begin, CompareLess<uptr>());
> + if (i < params->allocator_caches.size() &&
> + params->allocator_caches[i] >= begin &&
> + end - params->allocator_caches[i] <= sizeof(AllocatorCache)) {
> + // Split the range in two and omit the allocator cache within.
> + ScanRangeForPointers(begin, params->allocator_caches[i],
> + ¶ms->argument->frontier, "TLS", kReachable);
> + uptr begin2 = params->allocator_caches[i] + sizeof(AllocatorCache);
> + ScanRangeForPointers(begin2, end, ¶ms->argument->frontier, "TLS",
> + kReachable);
> + } else {
> + ScanRangeForPointers(begin, end, ¶ms->argument->frontier, "TLS",
> + kReachable);
> + }
> + };
> +
> + // This stops the world and then makes callbacks for various memory regions.
> + // The final callback is the last thing before the world starts up again.
> + __sanitizer_memory_snapshot(
> + flags()->use_globals ? globals : nullptr,
> + flags()->use_stacks ? stacks : nullptr,
> + flags()->use_registers ? registers : nullptr,
> + flags()->use_tls ? tls : nullptr,
> + [](zx_status_t, void *data) {
> + auto params = static_cast<const Params *>(data);
> +
> + // We don't use the thread registry at all for enumerating the threads
> + // and their stacks, registers, and TLS regions. So use it separately
> + // just for the allocator cache, and to call ForEachExtraStackRange,
> + // which ASan needs.
> + if (flags()->use_stacks) {
> + GetThreadRegistryLocked()->RunCallbackForEachThreadLocked(
> + [](ThreadContextBase *tctx, void *arg) {
> + ForEachExtraStackRange(tctx->os_id, ForEachExtraStackRangeCb,
> + arg);
> + },
> + ¶ms->argument->frontier);
> + }
> +
> + params->callback({}, params->argument);
> + },
> + ¶ms);
> +
> + UnlockAllocator();
> + UnlockThreadRegistry();
> +}
> +
> +} // namespace __lsan
> +
> +// This is declared (in extern "C") by <zircon/sanitizer.h>.
> +// _Exit calls this directly to intercept and change the status value.
> +int __sanitizer_process_exit_hook(int status) {
> + return __lsan::ExitHook(status);
> +}
> +
> +#endif
> diff --git a/libsanitizer/lsan/lsan_common_linux.cpp b/libsanitizer/lsan/lsan_common_linux.cpp
> index ea1a4a2f569..c97ef31593d 100644
> --- a/libsanitizer/lsan/lsan_common_linux.cpp
> +++ b/libsanitizer/lsan/lsan_common_linux.cpp
> @@ -134,7 +134,8 @@ static int LockStuffAndStopTheWorldCallback(struct dl_phdr_info *info,
> // while holding the libdl lock in the parent thread, we can safely reenter it
> // in the tracer. The solution is to run stoptheworld from a dl_iterate_phdr()
> // callback in the parent thread.
> -void LockStuffAndStopTheWorld(StopTheWorldCallback callback, void *argument) {
> +void LockStuffAndStopTheWorld(StopTheWorldCallback callback,
> + CheckForLeaksParam *argument) {
> DoStopTheWorldParam param = {callback, argument};
> dl_iterate_phdr(LockStuffAndStopTheWorldCallback, ¶m);
> }
> diff --git a/libsanitizer/lsan/lsan_common_mac.cpp b/libsanitizer/lsan/lsan_common_mac.cpp
> index c1804e93c11..8516a176eb4 100644
> --- a/libsanitizer/lsan/lsan_common_mac.cpp
> +++ b/libsanitizer/lsan/lsan_common_mac.cpp
> @@ -193,7 +193,8 @@ void ProcessPlatformSpecificAllocations(Frontier *frontier) {
> // causes rare race conditions.
> void HandleLeaks() {}
>
> -void LockStuffAndStopTheWorld(StopTheWorldCallback callback, void *argument) {
> +void LockStuffAndStopTheWorld(StopTheWorldCallback callback,
> + CheckForLeaksParam *argument) {
> LockThreadRegistry();
> LockAllocator();
> StopTheWorld(callback, argument);
> diff --git a/libsanitizer/lsan/lsan_fuchsia.cpp b/libsanitizer/lsan/lsan_fuchsia.cpp
> new file mode 100644
> index 00000000000..40e65c6fb72
> --- /dev/null
> +++ b/libsanitizer/lsan/lsan_fuchsia.cpp
> @@ -0,0 +1,123 @@
> +//=-- lsan_fuchsia.cpp ---------------------------------------------------===//
> +//
> +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
> +// See https://llvm.org/LICENSE.txt for license information.
> +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
> +//
> +//===---------------------------------------------------------------------===//
> +//
> +// This file is a part of LeakSanitizer.
> +// Standalone LSan RTL code specific to Fuchsia.
> +//
> +//===---------------------------------------------------------------------===//
> +
> +#include "sanitizer_common/sanitizer_platform.h"
> +
> +#if SANITIZER_FUCHSIA
> +#include <zircon/sanitizer.h>
> +
> +#include "lsan.h"
> +#include "lsan_allocator.h"
> +
> +using namespace __lsan;
> +
> +namespace __lsan {
> +
> +void LsanOnDeadlySignal(int signo, void *siginfo, void *context) {}
> +
> +ThreadContext::ThreadContext(int tid) : ThreadContextLsanBase(tid) {}
> +
> +struct OnCreatedArgs {
> + uptr stack_begin, stack_end;
> +};
> +
> +// On Fuchsia, the stack bounds of a new thread are available before
> +// the thread itself has started running.
> +void ThreadContext::OnCreated(void *arg) {
> + // Stack bounds passed through from __sanitizer_before_thread_create_hook
> + // or InitializeMainThread.
> + auto args = reinterpret_cast<const OnCreatedArgs *>(arg);
> + stack_begin_ = args->stack_begin;
> + stack_end_ = args->stack_end;
> +}
> +
> +struct OnStartedArgs {
> + uptr cache_begin, cache_end;
> +};
> +
> +void ThreadContext::OnStarted(void *arg) {
> + auto args = reinterpret_cast<const OnStartedArgs *>(arg);
> + cache_begin_ = args->cache_begin;
> + cache_end_ = args->cache_end;
> +}
> +
> +void ThreadStart(u32 tid) {
> + OnStartedArgs args;
> + GetAllocatorCacheRange(&args.cache_begin, &args.cache_end);
> + CHECK_EQ(args.cache_end - args.cache_begin, sizeof(AllocatorCache));
> + ThreadContextLsanBase::ThreadStart(tid, GetTid(), ThreadType::Regular, &args);
> +}
> +
> +void InitializeMainThread() {
> + OnCreatedArgs args;
> + __sanitizer::GetThreadStackTopAndBottom(true, &args.stack_end,
> + &args.stack_begin);
> + u32 tid = ThreadCreate(0, GetThreadSelf(), true, &args);
> + CHECK_EQ(tid, 0);
> + ThreadStart(tid);
> +}
> +
> +void GetAllThreadAllocatorCachesLocked(InternalMmapVector<uptr> *caches) {
> + GetThreadRegistryLocked()->RunCallbackForEachThreadLocked(
> + [](ThreadContextBase *tctx, void *arg) {
> + auto ctx = static_cast<ThreadContext *>(tctx);
> + static_cast<decltype(caches)>(arg)->push_back(ctx->cache_begin());
> + },
> + caches);
> +}
> +
> +} // namespace __lsan
> +
> +// These are declared (in extern "C") by <zircon/sanitizer.h>.
> +// The system runtime will call our definitions directly.
> +
> +// This is called before each thread creation is attempted. So, in
> +// its first call, the calling thread is the initial and sole thread.
> +void *__sanitizer_before_thread_create_hook(thrd_t thread, bool detached,
> + const char *name, void *stack_base,
> + size_t stack_size) {
> + uptr user_id = reinterpret_cast<uptr>(thread);
> + ENSURE_LSAN_INITED;
> + EnsureMainThreadIDIsCorrect();
> + OnCreatedArgs args;
> + args.stack_begin = reinterpret_cast<uptr>(stack_base);
> + args.stack_end = args.stack_begin + stack_size;
> + u32 parent_tid = GetCurrentThread();
> + u32 tid = ThreadCreate(parent_tid, user_id, detached, &args);
> + return reinterpret_cast<void *>(static_cast<uptr>(tid));
> +}
> +
> +// This is called after creating a new thread (in the creating thread),
> +// with the pointer returned by __sanitizer_before_thread_create_hook (above).
> +void __sanitizer_thread_create_hook(void *hook, thrd_t thread, int error) {
> + u32 tid = static_cast<u32>(reinterpret_cast<uptr>(hook));
> + // On success, there is nothing to do here.
> + if (error != thrd_success) {
> + // Clean up the thread registry for the thread creation that didn't happen.
> + GetThreadRegistryLocked()->FinishThread(tid);
> + }
> +}
> +
> +// This is called in the newly-created thread before it runs anything else,
> +// with the pointer returned by __sanitizer_before_thread_create_hook (above).
> +void __sanitizer_thread_start_hook(void *hook, thrd_t self) {
> + u32 tid = static_cast<u32>(reinterpret_cast<uptr>(hook));
> + ThreadStart(tid);
> +}
> +
> +// Each thread runs this just before it exits,
> +// with the pointer returned by BeforeThreadCreateHook (above).
> +// All per-thread destructors have already been called.
> +void __sanitizer_thread_exit_hook(void *hook, thrd_t self) { ThreadFinish(); }
> +
> +#endif // SANITIZER_FUCHSIA
> diff --git a/libsanitizer/lsan/lsan_fuchsia.h b/libsanitizer/lsan/lsan_fuchsia.h
> new file mode 100644
> index 00000000000..65d20ea2114
> --- /dev/null
> +++ b/libsanitizer/lsan/lsan_fuchsia.h
> @@ -0,0 +1,35 @@
> +//=-- lsan_fuchsia.h ---------------------------------------------------===//
> +//
> +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
> +// See https://llvm.org/LICENSE.txt for license information.
> +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
> +//
> +//===---------------------------------------------------------------------===//
> +//
> +// This file is a part of LeakSanitizer.
> +// Standalone LSan RTL code specific to Fuchsia.
> +//
> +//===---------------------------------------------------------------------===//
> +
> +#ifndef LSAN_FUCHSIA_H
> +#define LSAN_FUCHSIA_H
> +
> +#include "lsan_thread.h"
> +#include "sanitizer_common/sanitizer_platform.h"
> +
> +#if !SANITIZER_FUCHSIA
> +#error "lsan_fuchsia.h is used only on Fuchsia systems (SANITIZER_FUCHSIA)"
> +#endif
> +
> +namespace __lsan {
> +
> +class ThreadContext : public ThreadContextLsanBase {
> + public:
> + explicit ThreadContext(int tid);
> + void OnCreated(void *arg) override;
> + void OnStarted(void *arg) override;
> +};
> +
> +} // namespace __lsan
> +
> +#endif // LSAN_FUCHSIA_H
> diff --git a/libsanitizer/lsan/lsan_interceptors.cpp b/libsanitizer/lsan/lsan_interceptors.cpp
> index f642bb807bc..9ce9b78c5a5 100644
> --- a/libsanitizer/lsan/lsan_interceptors.cpp
> +++ b/libsanitizer/lsan/lsan_interceptors.cpp
> @@ -22,7 +22,9 @@
> #include "sanitizer_common/sanitizer_platform_interceptors.h"
> #include "sanitizer_common/sanitizer_platform_limits_netbsd.h"
> #include "sanitizer_common/sanitizer_platform_limits_posix.h"
> +#if SANITIZER_POSIX
> #include "sanitizer_common/sanitizer_posix.h"
> +#endif
> #include "sanitizer_common/sanitizer_tls_get_addr.h"
> #include "lsan.h"
> #include "lsan_allocator.h"
> @@ -61,6 +63,9 @@ INTERCEPTOR(void, free, void *p) {
> }
>
> INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {
> + // This hack is not required for Fuchsia because there are no dlsym calls
> + // involved in setting up interceptors.
> +#if !SANITIZER_FUCHSIA
> if (lsan_init_is_running) {
> // Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym.
> const uptr kCallocPoolSize = 1024;
> @@ -72,6 +77,7 @@ INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {
> CHECK(allocated < kCallocPoolSize);
> return mem;
> }
> +#endif // !SANITIZER_FUCHSIA
> ENSURE_LSAN_INITED;
> GET_STACK_TRACE_MALLOC;
> return lsan_calloc(nmemb, size, stack);
> @@ -100,7 +106,7 @@ INTERCEPTOR(void*, valloc, uptr size) {
> GET_STACK_TRACE_MALLOC;
> return lsan_valloc(size, stack);
> }
> -#endif
> +#endif // !SANITIZER_MAC
>
> #if SANITIZER_INTERCEPT_MEMALIGN
> INTERCEPTOR(void*, memalign, uptr alignment, uptr size) {
> @@ -307,7 +313,7 @@ INTERCEPTOR(void, _ZdaPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&)
>
> ///// Thread initialization and finalization. /////
>
> -#if !SANITIZER_NETBSD && !SANITIZER_FREEBSD
> +#if !SANITIZER_NETBSD && !SANITIZER_FREEBSD && !SANITIZER_FUCHSIA
> static unsigned g_thread_finalize_key;
>
> static void thread_finalize(void *v) {
> @@ -394,6 +400,8 @@ INTERCEPTOR(char *, strerror, int errnum) {
> #define LSAN_MAYBE_INTERCEPT_STRERROR
> #endif
>
> +#if SANITIZER_POSIX
> +
> struct ThreadParam {
> void *(*callback)(void *arg);
> void *param;
> @@ -416,7 +424,6 @@ extern "C" void *__lsan_thread_start_func(void *arg) {
> int tid = 0;
> while ((tid = atomic_load(&p->tid, memory_order_acquire)) == 0)
> internal_sched_yield();
> - SetCurrentThread(tid);
> ThreadStart(tid, GetTid());
> atomic_store(&p->tid, 0, memory_order_release);
> return callback(param);
> @@ -477,9 +484,13 @@ INTERCEPTOR(void, _exit, int status) {
> #define COMMON_INTERCEPT_FUNCTION(name) INTERCEPT_FUNCTION(name)
> #include "sanitizer_common/sanitizer_signal_interceptors.inc"
>
> +#endif // SANITIZER_POSIX
> +
> namespace __lsan {
>
> void InitializeInterceptors() {
> + // Fuchsia doesn't use interceptors that require any setup.
> +#if !SANITIZER_FUCHSIA
> InitializeSignalInterceptors();
>
> INTERCEPT_FUNCTION(malloc);
> @@ -515,6 +526,8 @@ void InitializeInterceptors() {
> Die();
> }
> #endif
> +
> +#endif // !SANITIZER_FUCHSIA
> }
>
> } // namespace __lsan
> diff --git a/libsanitizer/lsan/lsan_linux.cpp b/libsanitizer/lsan/lsan_linux.cpp
> index 14a42b75d2a..47c2f21b5a6 100644
> --- a/libsanitizer/lsan/lsan_linux.cpp
> +++ b/libsanitizer/lsan/lsan_linux.cpp
> @@ -6,13 +6,13 @@
> //
> //===----------------------------------------------------------------------===//
> //
> -// This file is a part of LeakSanitizer. Linux/NetBSD-specific code.
> +// This file is a part of LeakSanitizer. Linux/NetBSD/Fuchsia-specific code.
> //
> //===----------------------------------------------------------------------===//
>
> #include "sanitizer_common/sanitizer_platform.h"
>
> -#if SANITIZER_LINUX || SANITIZER_NETBSD
> +#if SANITIZER_LINUX || SANITIZER_NETBSD || SANITIZER_FUCHSIA
>
> #include "lsan_allocator.h"
>
> @@ -29,4 +29,4 @@ void ReplaceSystemMalloc() {}
>
> } // namespace __lsan
>
> -#endif // SANITIZER_LINUX || SANITIZER_NETBSD
> +#endif // SANITIZER_LINUX || SANITIZER_NETBSD || SANITIZER_FUCHSIA
> diff --git a/libsanitizer/lsan/lsan_posix.cpp b/libsanitizer/lsan/lsan_posix.cpp
> new file mode 100644
> index 00000000000..8e05915dd1b
> --- /dev/null
> +++ b/libsanitizer/lsan/lsan_posix.cpp
> @@ -0,0 +1,96 @@
> +//=-- lsan_posix.cpp -----------------------------------------------------===//
> +//
> +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
> +// See https://llvm.org/LICENSE.txt for license information.
> +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
> +//
> +//===---------------------------------------------------------------------===//
> +//
> +// This file is a part of LeakSanitizer.
> +// Standalone LSan RTL code common to POSIX-like systems.
> +//
> +//===---------------------------------------------------------------------===//
> +
> +#include "sanitizer_common/sanitizer_platform.h"
> +
> +#if SANITIZER_POSIX
> +#include "lsan.h"
> +#include "lsan_allocator.h"
> +#include "sanitizer_common/sanitizer_stacktrace.h"
> +#include "sanitizer_common/sanitizer_tls_get_addr.h"
> +
> +namespace __lsan {
> +
> +ThreadContext::ThreadContext(int tid) : ThreadContextLsanBase(tid) {}
> +
> +struct OnStartedArgs {
> + uptr stack_begin;
> + uptr stack_end;
> + uptr cache_begin;
> + uptr cache_end;
> + uptr tls_begin;
> + uptr tls_end;
> + DTLS *dtls;
> +};
> +
> +void ThreadContext::OnStarted(void *arg) {
> + auto args = reinterpret_cast<const OnStartedArgs *>(arg);
> + stack_begin_ = args->stack_begin;
> + stack_end_ = args->stack_end;
> + tls_begin_ = args->tls_begin;
> + tls_end_ = args->tls_end;
> + cache_begin_ = args->cache_begin;
> + cache_end_ = args->cache_end;
> + dtls_ = args->dtls;
> +}
> +
> +void ThreadStart(u32 tid, tid_t os_id, ThreadType thread_type) {
> + OnStartedArgs args;
> + uptr stack_size = 0;
> + uptr tls_size = 0;
> + GetThreadStackAndTls(tid == 0, &args.stack_begin, &stack_size,
> + &args.tls_begin, &tls_size);
> + args.stack_end = args.stack_begin + stack_size;
> + args.tls_end = args.tls_begin + tls_size;
> + GetAllocatorCacheRange(&args.cache_begin, &args.cache_end);
> + args.dtls = DTLS_Get();
> + ThreadContextLsanBase::ThreadStart(tid, os_id, thread_type, &args);
> +}
> +
> +bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end,
> + uptr *tls_begin, uptr *tls_end, uptr *cache_begin,
> + uptr *cache_end, DTLS **dtls) {
> + ThreadContext *context = static_cast<ThreadContext *>(
> + GetThreadRegistryLocked()->FindThreadContextByOsIDLocked(os_id));
> + if (!context)
> + return false;
> + *stack_begin = context->stack_begin();
> + *stack_end = context->stack_end();
> + *tls_begin = context->tls_begin();
> + *tls_end = context->tls_end();
> + *cache_begin = context->cache_begin();
> + *cache_end = context->cache_end();
> + *dtls = context->dtls();
> + return true;
> +}
> +
> +void InitializeMainThread() {
> + u32 tid = ThreadCreate(0, 0, true);
> + CHECK_EQ(tid, 0);
> + ThreadStart(tid, GetTid());
> +}
> +
> +static void OnStackUnwind(const SignalContext &sig, const void *,
> + BufferedStackTrace *stack) {
> + stack->Unwind(StackTrace::GetNextInstructionPc(sig.pc), sig.bp, sig.context,
> + common_flags()->fast_unwind_on_fatal);
> +}
> +
> +void LsanOnDeadlySignal(int signo, void *siginfo, void *context) {
> + HandleDeadlySignal(siginfo, context, GetCurrentThread(), &OnStackUnwind,
> + nullptr);
> +}
> +
> +} // namespace __lsan
> +
> +#endif // SANITIZER_POSIX
> diff --git a/libsanitizer/lsan/lsan_posix.h b/libsanitizer/lsan/lsan_posix.h
> new file mode 100644
> index 00000000000..840e427c55e
> --- /dev/null
> +++ b/libsanitizer/lsan/lsan_posix.h
> @@ -0,0 +1,49 @@
> +//=-- lsan_posix.h -----------------------------------------------------===//
> +//
> +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
> +// See https://llvm.org/LICENSE.txt for license information.
> +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
> +//
> +//===---------------------------------------------------------------------===//
> +//
> +// This file is a part of LeakSanitizer.
> +// Standalone LSan RTL code common to POSIX-like systems.
> +//
> +//===---------------------------------------------------------------------===//
> +
> +#ifndef LSAN_POSIX_H
> +#define LSAN_POSIX_H
> +
> +#include "lsan_thread.h"
> +#include "sanitizer_common/sanitizer_platform.h"
> +
> +#if !SANITIZER_POSIX
> +#error "lsan_posix.h is used only on POSIX-like systems (SANITIZER_POSIX)"
> +#endif
> +
> +namespace __sanitizer {
> +struct DTLS;
> +}
> +
> +namespace __lsan {
> +
> +class ThreadContext : public ThreadContextLsanBase {
> + public:
> + explicit ThreadContext(int tid);
> + void OnStarted(void *arg) override;
> + uptr tls_begin() { return tls_begin_; }
> + uptr tls_end() { return tls_end_; }
> + DTLS *dtls() { return dtls_; }
> +
> + private:
> + uptr tls_begin_ = 0;
> + uptr tls_end_ = 0;
> + DTLS *dtls_ = nullptr;
> +};
> +
> +void ThreadStart(u32 tid, tid_t os_id,
> + ThreadType thread_type = ThreadType::Regular);
> +
> +} // namespace __lsan
> +
> +#endif // LSAN_POSIX_H
> diff --git a/libsanitizer/lsan/lsan_thread.cpp b/libsanitizer/lsan/lsan_thread.cpp
> index 84e7ce61b97..40bdc254bb6 100644
> --- a/libsanitizer/lsan/lsan_thread.cpp
> +++ b/libsanitizer/lsan/lsan_thread.cpp
> @@ -13,12 +13,13 @@
>
> #include "lsan_thread.h"
>
> +#include "lsan.h"
> +#include "lsan_allocator.h"
> +#include "lsan_common.h"
> #include "sanitizer_common/sanitizer_common.h"
> #include "sanitizer_common/sanitizer_placement_new.h"
> #include "sanitizer_common/sanitizer_thread_registry.h"
> #include "sanitizer_common/sanitizer_tls_get_addr.h"
> -#include "lsan_allocator.h"
> -#include "lsan_common.h"
>
> namespace __lsan {
>
> @@ -26,7 +27,7 @@ static ThreadRegistry *thread_registry;
>
> static ThreadContextBase *CreateThreadContext(u32 tid) {
> void *mem = MmapOrDie(sizeof(ThreadContext), "ThreadContext");
> - return new(mem) ThreadContext(tid);
> + return new (mem) ThreadContext(tid);
> }
>
> static const uptr kMaxThreads = 1 << 13;
> @@ -34,59 +35,26 @@ static const uptr kThreadQuarantineSize = 64;
>
> void InitializeThreadRegistry() {
> static ALIGNED(64) char thread_registry_placeholder[sizeof(ThreadRegistry)];
> - thread_registry = new(thread_registry_placeholder)
> - ThreadRegistry(CreateThreadContext, kMaxThreads, kThreadQuarantineSize);
> + thread_registry = new (thread_registry_placeholder)
> + ThreadRegistry(CreateThreadContext, kMaxThreads, kThreadQuarantineSize);
> }
>
> -ThreadContext::ThreadContext(int tid)
> - : ThreadContextBase(tid),
> - stack_begin_(0),
> - stack_end_(0),
> - cache_begin_(0),
> - cache_end_(0),
> - tls_begin_(0),
> - tls_end_(0),
> - dtls_(nullptr) {}
> -
> -struct OnStartedArgs {
> - uptr stack_begin, stack_end,
> - cache_begin, cache_end,
> - tls_begin, tls_end;
> - DTLS *dtls;
> -};
> -
> -void ThreadContext::OnStarted(void *arg) {
> - OnStartedArgs *args = reinterpret_cast<OnStartedArgs *>(arg);
> - stack_begin_ = args->stack_begin;
> - stack_end_ = args->stack_end;
> - tls_begin_ = args->tls_begin;
> - tls_end_ = args->tls_end;
> - cache_begin_ = args->cache_begin;
> - cache_end_ = args->cache_end;
> - dtls_ = args->dtls;
> -}
> +ThreadContextLsanBase::ThreadContextLsanBase(int tid)
> + : ThreadContextBase(tid) {}
>
> -void ThreadContext::OnFinished() {
> +void ThreadContextLsanBase::OnFinished() {
> AllocatorThreadFinish();
> DTLS_Destroy();
> }
>
> -u32 ThreadCreate(u32 parent_tid, uptr user_id, bool detached) {
> - return thread_registry->CreateThread(user_id, detached, parent_tid,
> - /* arg */ nullptr);
> +u32 ThreadCreate(u32 parent_tid, uptr user_id, bool detached, void *arg) {
> + return thread_registry->CreateThread(user_id, detached, parent_tid, arg);
> }
>
> -void ThreadStart(u32 tid, tid_t os_id, ThreadType thread_type) {
> - OnStartedArgs args;
> - uptr stack_size = 0;
> - uptr tls_size = 0;
> - GetThreadStackAndTls(tid == 0, &args.stack_begin, &stack_size,
> - &args.tls_begin, &tls_size);
> - args.stack_end = args.stack_begin + stack_size;
> - args.tls_end = args.tls_begin + tls_size;
> - GetAllocatorCacheRange(&args.cache_begin, &args.cache_end);
> - args.dtls = DTLS_Get();
> - thread_registry->StartThread(tid, os_id, thread_type, &args);
> +void ThreadContextLsanBase::ThreadStart(u32 tid, tid_t os_id,
> + ThreadType thread_type, void *arg) {
> + thread_registry->StartThread(tid, os_id, thread_type, arg);
> + SetCurrentThread(tid);
> }
>
> void ThreadFinish() {
> @@ -95,7 +63,8 @@ void ThreadFinish() {
> }
>
> ThreadContext *CurrentThreadContext() {
> - if (!thread_registry) return nullptr;
> + if (!thread_registry)
> + return nullptr;
> if (GetCurrentThread() == kInvalidTid)
> return nullptr;
> // No lock needed when getting current thread.
> @@ -111,12 +80,12 @@ static bool FindThreadByUid(ThreadContextBase *tctx, void *arg) {
> }
>
> u32 ThreadTid(uptr uid) {
> - return thread_registry->FindThread(FindThreadByUid, (void*)uid);
> + return thread_registry->FindThread(FindThreadByUid, (void *)uid);
> }
>
> void ThreadJoin(u32 tid) {
> CHECK_NE(tid, kInvalidTid);
> - thread_registry->JoinThread(tid, /* arg */nullptr);
> + thread_registry->JoinThread(tid, /* arg */ nullptr);
> }
>
> void EnsureMainThreadIDIsCorrect() {
> @@ -126,37 +95,16 @@ void EnsureMainThreadIDIsCorrect() {
>
> ///// Interface to the common LSan module. /////
>
> -bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end,
> - uptr *tls_begin, uptr *tls_end, uptr *cache_begin,
> - uptr *cache_end, DTLS **dtls) {
> - ThreadContext *context = static_cast<ThreadContext *>(
> - thread_registry->FindThreadContextByOsIDLocked(os_id));
> - if (!context) return false;
> - *stack_begin = context->stack_begin();
> - *stack_end = context->stack_end();
> - *tls_begin = context->tls_begin();
> - *tls_end = context->tls_end();
> - *cache_begin = context->cache_begin();
> - *cache_end = context->cache_end();
> - *dtls = context->dtls();
> - return true;
> -}
> -
> void ForEachExtraStackRange(tid_t os_id, RangeIteratorCallback callback,
> - void *arg) {
> -}
> + void *arg) {}
>
> -void LockThreadRegistry() {
> - thread_registry->Lock();
> -}
> +void LockThreadRegistry() { thread_registry->Lock(); }
>
> -void UnlockThreadRegistry() {
> - thread_registry->Unlock();
> -}
> +void UnlockThreadRegistry() { thread_registry->Unlock(); }
>
> ThreadRegistry *GetThreadRegistryLocked() {
> thread_registry->CheckLocked();
> return thread_registry;
> }
>
> -} // namespace __lsan
> +} // namespace __lsan
> diff --git a/libsanitizer/lsan/lsan_thread.h b/libsanitizer/lsan/lsan_thread.h
> index b869d066d9d..0ab1582de66 100644
> --- a/libsanitizer/lsan/lsan_thread.h
> +++ b/libsanitizer/lsan/lsan_thread.h
> @@ -16,38 +16,36 @@
>
> #include "sanitizer_common/sanitizer_thread_registry.h"
>
> -namespace __sanitizer {
> -struct DTLS;
> -}
> -
> namespace __lsan {
>
> -class ThreadContext : public ThreadContextBase {
> +class ThreadContextLsanBase : public ThreadContextBase {
> public:
> - explicit ThreadContext(int tid);
> - void OnStarted(void *arg) override;
> + explicit ThreadContextLsanBase(int tid);
> void OnFinished() override;
> uptr stack_begin() { return stack_begin_; }
> uptr stack_end() { return stack_end_; }
> - uptr tls_begin() { return tls_begin_; }
> - uptr tls_end() { return tls_end_; }
> uptr cache_begin() { return cache_begin_; }
> uptr cache_end() { return cache_end_; }
> - DTLS *dtls() { return dtls_; }
>
> - private:
> - uptr stack_begin_, stack_end_,
> - cache_begin_, cache_end_,
> - tls_begin_, tls_end_;
> - DTLS *dtls_;
> + // The argument is passed on to the subclass's OnStarted member function.
> + static void ThreadStart(u32 tid, tid_t os_id, ThreadType thread_type,
> + void *onstarted_arg);
> +
> + protected:
> + uptr stack_begin_ = 0;
> + uptr stack_end_ = 0;
> + uptr cache_begin_ = 0;
> + uptr cache_end_ = 0;
> };
>
> +// This subclass of ThreadContextLsanBase is declared in an OS-specific header.
> +class ThreadContext;
> +
> void InitializeThreadRegistry();
> +void InitializeMainThread();
>
> -void ThreadStart(u32 tid, tid_t os_id,
> - ThreadType thread_type = ThreadType::Regular);
> +u32 ThreadCreate(u32 tid, uptr uid, bool detached, void *arg = nullptr);
> void ThreadFinish();
> -u32 ThreadCreate(u32 tid, uptr uid, bool detached);
> void ThreadJoin(u32 tid);
> u32 ThreadTid(uptr uid);
>
> @@ -55,6 +53,7 @@ u32 GetCurrentThread();
> void SetCurrentThread(u32 tid);
> ThreadContext *CurrentThreadContext();
> void EnsureMainThreadIDIsCorrect();
> +
> } // namespace __lsan
>
> #endif // LSAN_THREAD_H
> diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator.cpp b/libsanitizer/sanitizer_common/sanitizer_allocator.cpp
> index 8d07906cca0..ec77b9cbfee 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_allocator.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_allocator.cpp
> @@ -25,7 +25,7 @@ const char *PrimaryAllocatorName = "SizeClassAllocator";
> const char *SecondaryAllocatorName = "LargeMmapAllocator";
>
> // ThreadSanitizer for Go uses libc malloc/free.
> -#if SANITIZER_GO || defined(SANITIZER_USE_MALLOC)
> +#if defined(SANITIZER_USE_MALLOC)
> # if SANITIZER_LINUX && !SANITIZER_ANDROID
> extern "C" void *__libc_malloc(uptr size);
> # if !SANITIZER_GO
> @@ -213,7 +213,7 @@ void *LowLevelAllocator::Allocate(uptr size) {
> // Align allocation size.
> size = RoundUpTo(size, low_level_alloc_min_alignment);
> if (allocated_end_ - allocated_current_ < (sptr)size) {
> - uptr size_to_allocate = Max(size, GetPageSizeCached());
> + uptr size_to_allocate = RoundUpTo(size, GetPageSizeCached());
> allocated_current_ =
> (char*)MmapOrDie(size_to_allocate, __func__);
> allocated_end_ = allocated_current_ + size_to_allocate;
> diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_primary64.h b/libsanitizer/sanitizer_common/sanitizer_allocator_primary64.h
> index 90603280e7c..1d9a29c70f3 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_allocator_primary64.h
> +++ b/libsanitizer/sanitizer_common/sanitizer_allocator_primary64.h
> @@ -72,11 +72,15 @@ class SizeClassAllocator64 {
> void Init(s32 release_to_os_interval_ms) {
> uptr TotalSpaceSize = kSpaceSize + AdditionalSize();
> if (kUsingConstantSpaceBeg) {
> + CHECK(IsAligned(kSpaceBeg, SizeClassMap::kMaxSize));
> CHECK_EQ(kSpaceBeg, address_range.Init(TotalSpaceSize,
> PrimaryAllocatorName, kSpaceBeg));
> } else {
> - NonConstSpaceBeg = address_range.Init(TotalSpaceSize,
> - PrimaryAllocatorName);
> + // Combined allocator expects that an 2^N allocation is always aligned to
> + // 2^N. For this to work, the start of the space needs to be aligned as
> + // high as the largest size class (which also needs to be a power of 2).
> + NonConstSpaceBeg = address_range.InitAligned(
> + TotalSpaceSize, SizeClassMap::kMaxSize, PrimaryAllocatorName);
> CHECK_NE(NonConstSpaceBeg, ~(uptr)0);
> }
> SetReleaseToOSIntervalMs(release_to_os_interval_ms);
> @@ -220,7 +224,7 @@ class SizeClassAllocator64 {
>
> // Test-only.
> void TestOnlyUnmap() {
> - UnmapWithCallbackOrDie(SpaceBeg(), kSpaceSize + AdditionalSize());
> + UnmapWithCallbackOrDie((uptr)address_range.base(), address_range.size());
> }
>
> static void FillMemoryProfile(uptr start, uptr rss, bool file, uptr *stats,
> diff --git a/libsanitizer/sanitizer_common/sanitizer_common.cpp b/libsanitizer/sanitizer_common/sanitizer_common.cpp
> index f5f9f49d8cf..87efda5bd37 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_common.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_common.cpp
> @@ -274,6 +274,7 @@ uptr ReadBinaryNameCached(/*out*/char *buf, uptr buf_len) {
> return name_len;
> }
>
> +#if !SANITIZER_GO
> void PrintCmdline() {
> char **argv = GetArgv();
> if (!argv) return;
> @@ -282,6 +283,7 @@ void PrintCmdline() {
> Printf("%s ", argv[i]);
> Printf("\n\n");
> }
> +#endif
>
> // Malloc hooks.
> static const int kMaxMallocFreeHooks = 5;
> diff --git a/libsanitizer/sanitizer_common/sanitizer_common.h b/libsanitizer/sanitizer_common/sanitizer_common.h
> index 87b8f02b5b7..ac16e0e47ef 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_common.h
> +++ b/libsanitizer/sanitizer_common/sanitizer_common.h
> @@ -143,6 +143,7 @@ void RunFreeHooks(const void *ptr);
> class ReservedAddressRange {
> public:
> uptr Init(uptr size, const char *name = nullptr, uptr fixed_addr = 0);
> + uptr InitAligned(uptr size, uptr align, const char *name = nullptr);
> uptr Map(uptr fixed_addr, uptr size, const char *name = nullptr);
> uptr MapOrDie(uptr fixed_addr, uptr size, const char *name = nullptr);
> void Unmap(uptr addr, uptr size);
> @@ -552,7 +553,7 @@ bool operator!=(const InternalMmapVectorNoCtor<T> &lhs,
> template<typename T>
> class InternalMmapVector : public InternalMmapVectorNoCtor<T> {
> public:
> - InternalMmapVector() { InternalMmapVectorNoCtor<T>::Initialize(1); }
> + InternalMmapVector() { InternalMmapVectorNoCtor<T>::Initialize(0); }
> explicit InternalMmapVector(uptr cnt) {
> InternalMmapVectorNoCtor<T>::Initialize(cnt);
> this->resize(cnt);
> @@ -855,7 +856,7 @@ INLINE uptr GetPthreadDestructorIterations() {
> #endif
> }
>
> -void *internal_start_thread(void(*func)(void*), void *arg);
> +void *internal_start_thread(void *(*func)(void*), void *arg);
> void internal_join_thread(void *th);
> void MaybeStartBackgroudThread();
>
> diff --git a/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc b/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc
> index 50e3558b52e..57f8b2d2944 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc
> +++ b/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc
> @@ -79,13 +79,15 @@
> #define devname __devname50
> #define fgetpos __fgetpos50
> #define fsetpos __fsetpos50
> +#define fstatvfs __fstatvfs90
> +#define fstatvfs1 __fstatvfs190
> #define fts_children __fts_children60
> #define fts_close __fts_close60
> #define fts_open __fts_open60
> #define fts_read __fts_read60
> #define fts_set __fts_set60
> #define getitimer __getitimer50
> -#define getmntinfo __getmntinfo13
> +#define getmntinfo __getmntinfo90
> #define getpwent __getpwent50
> #define getpwnam __getpwnam50
> #define getpwnam_r __getpwnam_r50
> @@ -95,6 +97,7 @@
> #define getutxent __getutxent50
> #define getutxid __getutxid50
> #define getutxline __getutxline50
> +#define getvfsstat __getvfsstat90
> #define pututxline __pututxline50
> #define glob __glob30
> #define gmtime __gmtime50
> @@ -110,12 +113,15 @@
> #define setitimer __setitimer50
> #define setlocale __setlocale50
> #define shmctl __shmctl50
> +#define sigaltstack __sigaltstack14
> #define sigemptyset __sigemptyset14
> #define sigfillset __sigfillset14
> #define sigpending __sigpending14
> #define sigprocmask __sigprocmask14
> #define sigtimedwait __sigtimedwait50
> #define stat __stat50
> +#define statvfs __statvfs90
> +#define statvfs1 __statvfs190
> #define time __time50
> #define times __times13
> #define unvis __unvis50
> @@ -128,11 +134,7 @@ extern const short *_tolower_tab_;
>
> // Platform-specific options.
> #if SANITIZER_MAC
> -namespace __sanitizer {
> -bool PlatformHasDifferentMemcpyAndMemmove();
> -}
> -#define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE \
> - (__sanitizer::PlatformHasDifferentMemcpyAndMemmove())
> +#define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE false
> #elif SANITIZER_WINDOWS64
> #define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE false
> #else
> @@ -4177,11 +4179,27 @@ INTERCEPTOR(int, pthread_mutex_unlock, void *m) {
>
> #if SANITIZER_INTERCEPT___PTHREAD_MUTEX
> INTERCEPTOR(int, __pthread_mutex_lock, void *m) {
> - return WRAP(pthread_mutex_lock)(m);
> + void *ctx;
> + COMMON_INTERCEPTOR_ENTER(ctx, __pthread_mutex_lock, m);
> + COMMON_INTERCEPTOR_MUTEX_PRE_LOCK(ctx, 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_POST_LOCK(ctx, m);
> + if (res == errno_EINVAL)
> + COMMON_INTERCEPTOR_MUTEX_INVALID(ctx, m);
> + return res;
> }
>
> INTERCEPTOR(int, __pthread_mutex_unlock, void *m) {
> - return WRAP(pthread_mutex_unlock)(m);
> + void *ctx;
> + COMMON_INTERCEPTOR_ENTER(ctx, __pthread_mutex_unlock, m);
> + COMMON_INTERCEPTOR_MUTEX_UNLOCK(ctx, m);
> + int res = REAL(__pthread_mutex_unlock)(m);
> + if (res == errno_EINVAL)
> + COMMON_INTERCEPTOR_MUTEX_INVALID(ctx, m);
> + return res;
> }
>
> #define INIT___PTHREAD_MUTEX_LOCK \
> @@ -6411,12 +6429,11 @@ INTERCEPTOR(SSIZE_T, recvfrom, int fd, void *buf, SIZE_T len, int flags,
> if (srcaddr) srcaddr_sz = *addrlen;
> (void)srcaddr_sz; // prevent "set but not used" warning
> SSIZE_T res = REAL(recvfrom)(fd, buf, len, flags, srcaddr, addrlen);
> - if (res > 0) {
> + if (res > 0)
> COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, Min((SIZE_T)res, len));
> - if (srcaddr)
> - COMMON_INTERCEPTOR_INITIALIZE_RANGE(srcaddr,
> - Min((SIZE_T)*addrlen, srcaddr_sz));
> - }
> + if (res >= 0 && srcaddr)
> + COMMON_INTERCEPTOR_INITIALIZE_RANGE(srcaddr,
> + Min((SIZE_T)*addrlen, srcaddr_sz));
> return res;
> }
> #define INIT_RECV_RECVFROM \
> @@ -9623,6 +9640,148 @@ INTERCEPTOR(int, getentropy, void *buf, SIZE_T buflen) {
> #define INIT_GETENTROPY
> #endif
>
> +#if SANITIZER_INTERCEPT_QSORT
> +// Glibc qsort uses a temporary buffer allocated either on stack or on heap.
> +// Poisoned memory from there may get copied into the comparator arguments,
> +// where it needs to be dealt with. But even that is not enough - the results of
> +// the sort may be copied into the input/output array based on the results of
> +// the comparator calls, but directly from the temp memory, bypassing the
> +// unpoisoning done in wrapped_qsort_compar. We deal with this by, again,
> +// unpoisoning the entire array after the sort is done.
> +//
> +// We can not check that the entire array is initialized at the beginning. IMHO,
> +// it's fine for parts of the sorted objects to contain uninitialized memory,
> +// ex. as padding in structs.
> +typedef int (*qsort_compar_f)(const void *, const void *);
> +static THREADLOCAL qsort_compar_f qsort_compar;
> +static THREADLOCAL SIZE_T qsort_size;
> +int wrapped_qsort_compar(const void *a, const void *b) {
> + COMMON_INTERCEPTOR_UNPOISON_PARAM(2);
> + COMMON_INTERCEPTOR_INITIALIZE_RANGE(a, qsort_size);
> + COMMON_INTERCEPTOR_INITIALIZE_RANGE(b, qsort_size);
> + return qsort_compar(a, b);
> +}
> +
> +INTERCEPTOR(void, qsort, void *base, SIZE_T nmemb, SIZE_T size,
> + qsort_compar_f compar) {
> + void *ctx;
> + COMMON_INTERCEPTOR_ENTER(ctx, qsort, base, nmemb, size, compar);
> + // Run the comparator over all array elements to detect any memory issues.
> + if (nmemb > 1) {
> + for (SIZE_T i = 0; i < nmemb - 1; ++i) {
> + void *p = (void *)((char *)base + i * size);
> + void *q = (void *)((char *)base + (i + 1) * size);
> + COMMON_INTERCEPTOR_UNPOISON_PARAM(2);
> + compar(p, q);
> + }
> + }
> + qsort_compar_f old_compar = qsort_compar;
> + qsort_compar = compar;
> + SIZE_T old_size = qsort_size;
> + qsort_size = size;
> + REAL(qsort)(base, nmemb, size, wrapped_qsort_compar);
> + qsort_compar = old_compar;
> + qsort_size = old_size;
> + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, base, nmemb * size);
> +}
> +#define INIT_QSORT COMMON_INTERCEPT_FUNCTION(qsort)
> +#else
> +#define INIT_QSORT
> +#endif
> +
> +#if SANITIZER_INTERCEPT_QSORT_R
> +typedef int (*qsort_r_compar_f)(const void *, const void *, void *);
> +static THREADLOCAL qsort_r_compar_f qsort_r_compar;
> +static THREADLOCAL SIZE_T qsort_r_size;
> +int wrapped_qsort_r_compar(const void *a, const void *b, void *arg) {
> + COMMON_INTERCEPTOR_UNPOISON_PARAM(3);
> + COMMON_INTERCEPTOR_INITIALIZE_RANGE(a, qsort_r_size);
> + COMMON_INTERCEPTOR_INITIALIZE_RANGE(b, qsort_r_size);
> + return qsort_r_compar(a, b, arg);
> +}
> +
> +INTERCEPTOR(void, qsort_r, void *base, SIZE_T nmemb, SIZE_T size,
> + qsort_r_compar_f compar, void *arg) {
> + void *ctx;
> + COMMON_INTERCEPTOR_ENTER(ctx, qsort_r, base, nmemb, size, compar, arg);
> + // Run the comparator over all array elements to detect any memory issues.
> + if (nmemb > 1) {
> + for (SIZE_T i = 0; i < nmemb - 1; ++i) {
> + void *p = (void *)((char *)base + i * size);
> + void *q = (void *)((char *)base + (i + 1) * size);
> + COMMON_INTERCEPTOR_UNPOISON_PARAM(3);
> + compar(p, q, arg);
> + }
> + }
> + qsort_r_compar_f old_compar = qsort_r_compar;
> + qsort_r_compar = compar;
> + SIZE_T old_size = qsort_r_size;
> + qsort_r_size = size;
> + REAL(qsort_r)(base, nmemb, size, wrapped_qsort_r_compar, arg);
> + qsort_r_compar = old_compar;
> + qsort_r_size = old_size;
> + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, base, nmemb * size);
> +}
> +#define INIT_QSORT_R COMMON_INTERCEPT_FUNCTION(qsort_r)
> +#else
> +#define INIT_QSORT_R
> +#endif
> +
> +#if SANITIZER_INTERCEPT_SIGALTSTACK
> +INTERCEPTOR(int, sigaltstack, void *ss, void *oss) {
> + void *ctx;
> + COMMON_INTERCEPTOR_ENTER(ctx, sigaltstack, ss, oss);
> + int r = REAL(sigaltstack)(ss, oss);
> + if (r == 0 && oss != nullptr) {
> + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oss, struct_stack_t_sz);
> + }
> + return r;
> +}
> +#define INIT_SIGALTSTACK COMMON_INTERCEPT_FUNCTION(sigaltstack)
> +#else
> +#define INIT_SIGALTSTACK
> +#endif
> +
> +#if SANITIZER_INTERCEPT_UNAME
> +INTERCEPTOR(int, uname, struct utsname *utsname) {
> +#if SANITIZER_LINUX
> + if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED)
> + return internal_uname(utsname);
> +#endif
> + void *ctx;
> + COMMON_INTERCEPTOR_ENTER(ctx, uname, utsname);
> + int res = REAL(uname)(utsname);
> + if (!res)
> + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, utsname,
> + __sanitizer::struct_utsname_sz);
> + return res;
> +}
> +#define INIT_UNAME COMMON_INTERCEPT_FUNCTION(uname)
> +#else
> +#define INIT_UNAME
> +#endif
> +
> +#if SANITIZER_INTERCEPT___XUNAME
> +// FreeBSD's <sys/utsname.h> define uname() as
> +// static __inline int uname(struct utsname *name) {
> +// return __xuname(SYS_NMLN, (void*)name);
> +// }
> +INTERCEPTOR(int, __xuname, int size, void *utsname) {
> + void *ctx;
> + COMMON_INTERCEPTOR_ENTER(ctx, __xuname, size, utsname);
> + int res = REAL(__xuname)(size, utsname);
> + if (!res)
> + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, utsname,
> + __sanitizer::struct_utsname_sz);
> + return res;
> +}
> +#define INIT___XUNAME COMMON_INTERCEPT_FUNCTION(__xuname)
> +#else
> +#define INIT___XUNAME
> +#endif
> +
> +#include "sanitizer_common_interceptors_netbsd_compat.inc"
> +
> static void InitializeCommonInterceptors() {
> #if SI_POSIX
> static u64 metadata_mem[sizeof(MetadataHashMap) / sizeof(u64) + 1];
> @@ -9924,6 +10083,11 @@ static void InitializeCommonInterceptors() {
> INIT_CRYPT;
> INIT_CRYPT_R;
> INIT_GETENTROPY;
> + INIT_QSORT;
> + INIT_QSORT_R;
> + INIT_SIGALTSTACK;
> + INIT_UNAME;
> + INIT___XUNAME;
>
> INIT___PRINTF_CHK;
> }
> diff --git a/libsanitizer/sanitizer_common/sanitizer_common_interceptors_netbsd_compat.inc b/libsanitizer/sanitizer_common/sanitizer_common_interceptors_netbsd_compat.inc
> new file mode 100644
> index 00000000000..6aa73ec8c6a
> --- /dev/null
> +++ b/libsanitizer/sanitizer_common/sanitizer_common_interceptors_netbsd_compat.inc
> @@ -0,0 +1,128 @@
> +//===-- sanitizer_common_interceptors_netbsd_compat.inc ---------*- C++ -*-===//
> +//
> +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
> +// See https://llvm.org/LICENSE.txt for license information.
> +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
> +//
> +//===----------------------------------------------------------------------===//
> +//
> +// Common function interceptors for tools like AddressSanitizer,
> +// ThreadSanitizer, MemorySanitizer, etc.
> +//
> +// Interceptors for NetBSD old function calls that have been versioned.
> +//
> +// NetBSD minimal version supported 9.0.
> +// NetBSD current version supported 9.99.26.
> +//
> +//===----------------------------------------------------------------------===//
> +
> +#if SANITIZER_NETBSD
> +
> +// First undef all mangled symbols.
> +// Next, define compat interceptors.
> +// Finally, undef INIT_ and redefine it.
> +// This allows to avoid preprocessor issues.
> +
> +#undef fstatvfs
> +#undef fstatvfs1
> +#undef getmntinfo
> +#undef getvfsstat
> +#undef statvfs
> +#undef statvfs1
> +
> +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);
> + // FIXME: under ASan the call below may write to freed memory and corrupt
> + // its metadata. See
> + // https://github.com/google/sanitizers/issues/321.
> + int res = REAL(statvfs)(path, buf);
> + if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs90_sz);
> + return res;
> +}
> +
> +INTERCEPTOR(int, fstatvfs, int fd, void *buf) {
> + void *ctx;
> + COMMON_INTERCEPTOR_ENTER(ctx, fstatvfs, fd, buf);
> + COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
> + // FIXME: under ASan the call below may write to freed memory and corrupt
> + // its metadata. See
> + // https://github.com/google/sanitizers/issues/321.
> + int res = REAL(fstatvfs)(fd, buf);
> + if (!res) {
> + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs90_sz);
> + if (fd >= 0)
> + COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
> + }
> + return res;
> +}
> +
> +#undef INIT_STATVFS
> +#define INIT_STATVFS \
> + COMMON_INTERCEPT_FUNCTION(statvfs); \
> + COMMON_INTERCEPT_FUNCTION(fstatvfs); \
> + COMMON_INTERCEPT_FUNCTION(__statvfs90); \
> + COMMON_INTERCEPT_FUNCTION(__fstatvfs90)
> +
> +INTERCEPTOR(int, __getmntinfo13, void **mntbufp, int flags) {
> + void *ctx;
> + COMMON_INTERCEPTOR_ENTER(ctx, __getmntinfo13, mntbufp, flags);
> + int cnt = REAL(__getmntinfo13)(mntbufp, flags);
> + if (cnt > 0 && mntbufp) {
> + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mntbufp, sizeof(void *));
> + if (*mntbufp)
> + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *mntbufp, cnt * struct_statvfs90_sz);
> + }
> + return cnt;
> +}
> +
> +#undef INIT_GETMNTINFO
> +#define INIT_GETMNTINFO \
> + COMMON_INTERCEPT_FUNCTION(__getmntinfo13); \
> + COMMON_INTERCEPT_FUNCTION(__getmntinfo90)
> +
> +INTERCEPTOR(int, getvfsstat, void *buf, SIZE_T bufsize, int flags) {
> + void *ctx;
> + COMMON_INTERCEPTOR_ENTER(ctx, getvfsstat, buf, bufsize, flags);
> + int ret = REAL(getvfsstat)(buf, bufsize, flags);
> + if (buf && ret > 0)
> + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, ret * struct_statvfs90_sz);
> + return ret;
> +}
> +
> +#undef INIT_GETVFSSTAT
> +#define INIT_GETVFSSTAT \
> + COMMON_INTERCEPT_FUNCTION(getvfsstat); \
> + COMMON_INTERCEPT_FUNCTION(__getvfsstat90)
> +
> +INTERCEPTOR(int, statvfs1, const char *path, void *buf, int flags) {
> + void *ctx;
> + COMMON_INTERCEPTOR_ENTER(ctx, statvfs1, path, buf, flags);
> + if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
> + int res = REAL(statvfs1)(path, buf, flags);
> + if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs90_sz);
> + return res;
> +}
> +
> +INTERCEPTOR(int, fstatvfs1, int fd, void *buf, int flags) {
> + void *ctx;
> + COMMON_INTERCEPTOR_ENTER(ctx, fstatvfs1, fd, buf, flags);
> + COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
> + int res = REAL(fstatvfs1)(fd, buf, flags);
> + if (!res) {
> + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs90_sz);
> + if (fd >= 0)
> + COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
> + }
> + return res;
> +}
> +
> +#undef INIT_STATVFS1
> +#define INIT_STATVFS1 \
> + COMMON_INTERCEPT_FUNCTION(statvfs1); \
> + COMMON_INTERCEPT_FUNCTION(fstatvfs1); \
> + COMMON_INTERCEPT_FUNCTION(__statvfs190); \
> + COMMON_INTERCEPT_FUNCTION(__fstatvfs190)
> +
> +#endif
> diff --git a/libsanitizer/sanitizer_common/sanitizer_common_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_common_libcdep.cpp
> index 27d6a177760..0c918ebb4a9 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_common_libcdep.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_common_libcdep.cpp
> @@ -30,7 +30,7 @@ SANITIZER_WEAK_ATTRIBUTE StackDepotStats *StackDepotGetStats() {
> return nullptr;
> }
>
> -void BackgroundThread(void *arg) {
> +void *BackgroundThread(void *arg) {
> const uptr hard_rss_limit_mb = common_flags()->hard_rss_limit_mb;
> const uptr soft_rss_limit_mb = common_flags()->soft_rss_limit_mb;
> const bool heap_profile = common_flags()->heap_profile;
> @@ -129,6 +129,16 @@ void SetSandboxingCallback(void (*f)()) {
> sandboxing_callback = f;
> }
>
> +uptr ReservedAddressRange::InitAligned(uptr size, uptr align,
> + const char *name) {
> + CHECK(IsPowerOfTwo(align));
> + if (align <= GetPageSizeCached())
> + return Init(size, name);
> + uptr start = Init(size + align, name);
> + start += align - (start & (align - 1));
> + return start;
> +}
> +
> } // namespace __sanitizer
>
> SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_sandbox_on_notify,
> diff --git a/libsanitizer/sanitizer_common/sanitizer_common_syscalls.inc b/libsanitizer/sanitizer_common/sanitizer_common_syscalls.inc
> index 31ff48cfd2c..532ac9ead34 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_common_syscalls.inc
> +++ b/libsanitizer/sanitizer_common/sanitizer_common_syscalls.inc
> @@ -2885,6 +2885,23 @@ POST_SYSCALL(getrandom)(long res, void *buf, uptr count, long flags) {
> POST_WRITE(buf, res);
> }
> }
> +
> +PRE_SYSCALL(sigaltstack)(const void *ss, void *oss) {
> + if (ss != nullptr) {
> + PRE_READ(ss, struct_stack_t_sz);
> + }
> + if (oss != nullptr) {
> + PRE_WRITE(oss, struct_stack_t_sz);
> + }
> +}
> +
> +POST_SYSCALL(sigaltstack)(long res, void *ss, void *oss) {
> + if (res == 0) {
> + if (oss != nullptr) {
> + POST_WRITE(oss, struct_stack_t_sz);
> + }
> + }
> +}
> } // extern "C"
>
> #undef PRE_SYSCALL
> diff --git a/libsanitizer/sanitizer_common/sanitizer_coverage_fuchsia.cpp b/libsanitizer/sanitizer_common/sanitizer_coverage_fuchsia.cpp
> index f18cee66b84..a52db08433e 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_coverage_fuchsia.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_coverage_fuchsia.cpp
> @@ -27,15 +27,15 @@
>
> #include "sanitizer_platform.h"
> #if SANITIZER_FUCHSIA
> +#include <zircon/process.h>
> +#include <zircon/sanitizer.h>
> +#include <zircon/syscalls.h>
> +
> #include "sanitizer_atomic.h"
> #include "sanitizer_common.h"
> #include "sanitizer_internal_defs.h"
> #include "sanitizer_symbolizer_fuchsia.h"
>
> -#include <zircon/process.h>
> -#include <zircon/sanitizer.h>
> -#include <zircon/syscalls.h>
> -
> using namespace __sanitizer;
>
> namespace __sancov {
> @@ -82,7 +82,8 @@ class TracePcGuardController final {
> void TracePcGuard(u32 *guard, uptr pc) {
> atomic_uint32_t *guard_ptr = reinterpret_cast<atomic_uint32_t *>(guard);
> u32 idx = atomic_exchange(guard_ptr, 0, memory_order_relaxed);
> - if (idx > 0) array_[idx] = pc;
> + if (idx > 0)
> + array_[idx] = pc;
> }
>
> void Dump() {
> @@ -140,6 +141,10 @@ class TracePcGuardController final {
> internal_getpid());
> _zx_object_set_property(vmo_, ZX_PROP_NAME, vmo_name_,
> internal_strlen(vmo_name_));
> + uint64_t size = DataSize();
> + status = _zx_object_set_property(vmo_, ZX_PROP_VMO_CONTENT_SIZE, &size,
> + sizeof(size));
> + CHECK_EQ(status, ZX_OK);
>
> // Map the largest possible view we might need into the VMO. Later
> // we might need to increase the VMO's size before we can use larger
> @@ -172,6 +177,10 @@ class TracePcGuardController final {
>
> zx_status_t status = _zx_vmo_set_size(vmo_, DataSize());
> CHECK_EQ(status, ZX_OK);
> + uint64_t size = DataSize();
> + status = _zx_object_set_property(vmo_, ZX_PROP_VMO_CONTENT_SIZE, &size,
> + sizeof(size));
> + CHECK_EQ(status, ZX_OK);
>
> return first_index;
> }
> @@ -204,13 +213,15 @@ SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_dump_coverage(const uptr *pcs,
> }
>
> SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard, u32 *guard) {
> - if (!*guard) return;
> + if (!*guard)
> + return;
> __sancov::pc_guard_controller.TracePcGuard(guard, GET_CALLER_PC() - 1);
> }
>
> SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard_init,
> u32 *start, u32 *end) {
> - if (start == end || *start) return;
> + if (start == end || *start)
> + return;
> __sancov::pc_guard_controller.InitTracePcGuard(start, end);
> }
>
> diff --git a/libsanitizer/sanitizer_common/sanitizer_coverage_interface.inc b/libsanitizer/sanitizer_common/sanitizer_coverage_interface.inc
> index 7beeff7e8af..d7ab0c3d98c 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_coverage_interface.inc
> +++ b/libsanitizer/sanitizer_common/sanitizer_coverage_interface.inc
> @@ -29,4 +29,5 @@ INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_pc_guard_init)
> INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_pc_indir)
> INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_switch)
> INTERFACE_WEAK_FUNCTION(__sanitizer_cov_8bit_counters_init)
> +INTERFACE_WEAK_FUNCTION(__sanitizer_cov_bool_flag_init)
> INTERFACE_WEAK_FUNCTION(__sanitizer_cov_pcs_init)
> diff --git a/libsanitizer/sanitizer_common/sanitizer_coverage_libcdep_new.cpp b/libsanitizer/sanitizer_common/sanitizer_coverage_libcdep_new.cpp
> index 6a75792f926..73ebeb5fa14 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_coverage_libcdep_new.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_coverage_libcdep_new.cpp
> @@ -207,6 +207,7 @@ SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_div8, void) {}
> SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_gep, void) {}
> SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_indir, void) {}
> SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_8bit_counters_init, void) {}
> +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_bool_flag_init, void) {}
> SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_pcs_init, void) {}
> } // extern "C"
> // Weak definition for code instrumented with -fsanitize-coverage=stack-depth
> diff --git a/libsanitizer/sanitizer_common/sanitizer_file.h b/libsanitizer/sanitizer_common/sanitizer_file.h
> index 4a78a0e0ac8..26681f0493d 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_file.h
> +++ b/libsanitizer/sanitizer_common/sanitizer_file.h
> @@ -87,8 +87,8 @@ bool IsAbsolutePath(const char *path);
> // The child process will close all fds after STDERR_FILENO
> // before passing control to a program.
> pid_t StartSubprocess(const char *filename, const char *const argv[],
> - fd_t stdin_fd = kInvalidFd, fd_t stdout_fd = kInvalidFd,
> - fd_t stderr_fd = kInvalidFd);
> + const char *const envp[], fd_t stdin_fd = kInvalidFd,
> + fd_t stdout_fd = kInvalidFd, fd_t stderr_fd = kInvalidFd);
> // Checks if specified process is still running
> bool IsProcessRunning(pid_t pid);
> // Waits for the process to finish and returns its exit code.
> diff --git a/libsanitizer/sanitizer_common/sanitizer_flag_parser.cpp b/libsanitizer/sanitizer_common/sanitizer_flag_parser.cpp
> index 1e2bc665261..9e274268bf2 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_flag_parser.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_flag_parser.cpp
> @@ -56,9 +56,16 @@ char *FlagParser::ll_strndup(const char *s, uptr n) {
> }
>
> void FlagParser::PrintFlagDescriptions() {
> + char buffer[128];
> + buffer[sizeof(buffer) - 1] = '\0';
> Printf("Available flags for %s:\n", SanitizerToolName);
> - for (int i = 0; i < n_flags_; ++i)
> - Printf("\t%s\n\t\t- %s\n", flags_[i].name, flags_[i].desc);
> + for (int i = 0; i < n_flags_; ++i) {
> + bool truncated = !(flags_[i].handler->Format(buffer, sizeof(buffer)));
> + CHECK_EQ(buffer[sizeof(buffer) - 1], '\0');
> + const char *truncation_str = truncated ? " Truncated" : "";
> + Printf("\t%s\n\t\t- %s (Current Value%s: %s)\n", flags_[i].name,
> + flags_[i].desc, truncation_str, buffer);
> + }
> }
>
> void FlagParser::fatal_error(const char *err) {
> diff --git a/libsanitizer/sanitizer_common/sanitizer_flag_parser.h b/libsanitizer/sanitizer_common/sanitizer_flag_parser.h
> index c24ad25626b..fac5dff3463 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_flag_parser.h
> +++ b/libsanitizer/sanitizer_common/sanitizer_flag_parser.h
> @@ -22,9 +22,23 @@ namespace __sanitizer {
> class FlagHandlerBase {
> public:
> virtual bool Parse(const char *value) { return false; }
> + // Write the C string representation of the current value (truncated to fit)
> + // into the buffer of size `size`. Returns false if truncation occurred and
> + // returns true otherwise.
> + virtual bool Format(char *buffer, uptr size) {
> + if (size > 0)
> + buffer[0] = '\0';
> + return false;
> + }
>
> protected:
> ~FlagHandlerBase() {}
> +
> + inline bool FormatString(char *buffer, uptr size, const char *str_to_use) {
> + uptr num_symbols_should_write =
> + internal_snprintf(buffer, size, "%s", str_to_use);
> + return num_symbols_should_write < size;
> + }
> };
>
> template <typename T>
> @@ -34,6 +48,7 @@ class FlagHandler : public FlagHandlerBase {
> public:
> explicit FlagHandler(T *t) : t_(t) {}
> bool Parse(const char *value) final;
> + bool Format(char *buffer, uptr size) final;
> };
>
> inline bool ParseBool(const char *value, bool *b) {
> @@ -59,6 +74,11 @@ inline bool FlagHandler<bool>::Parse(const char *value) {
> return false;
> }
>
> +template <>
> +inline bool FlagHandler<bool>::Format(char *buffer, uptr size) {
> + return FormatString(buffer, size, *t_ ? "true" : "false");
> +}
> +
> template <>
> inline bool FlagHandler<HandleSignalMode>::Parse(const char *value) {
> bool b;
> @@ -75,12 +95,23 @@ inline bool FlagHandler<HandleSignalMode>::Parse(const char *value) {
> return false;
> }
>
> +template <>
> +inline bool FlagHandler<HandleSignalMode>::Format(char *buffer, uptr size) {
> + uptr num_symbols_should_write = internal_snprintf(buffer, size, "%d", *t_);
> + return num_symbols_should_write < size;
> +}
> +
> template <>
> inline bool FlagHandler<const char *>::Parse(const char *value) {
> *t_ = value;
> return true;
> }
>
> +template <>
> +inline bool FlagHandler<const char *>::Format(char *buffer, uptr size) {
> + return FormatString(buffer, size, *t_);
> +}
> +
> template <>
> inline bool FlagHandler<int>::Parse(const char *value) {
> const char *value_end;
> @@ -90,6 +121,12 @@ inline bool FlagHandler<int>::Parse(const char *value) {
> return ok;
> }
>
> +template <>
> +inline bool FlagHandler<int>::Format(char *buffer, uptr size) {
> + uptr num_symbols_should_write = internal_snprintf(buffer, size, "%d", *t_);
> + return num_symbols_should_write < size;
> +}
> +
> template <>
> inline bool FlagHandler<uptr>::Parse(const char *value) {
> const char *value_end;
> @@ -99,6 +136,12 @@ inline bool FlagHandler<uptr>::Parse(const char *value) {
> return ok;
> }
>
> +template <>
> +inline bool FlagHandler<uptr>::Format(char *buffer, uptr size) {
> + uptr num_symbols_should_write = internal_snprintf(buffer, size, "%p", *t_);
> + return num_symbols_should_write < size;
> +}
> +
> template <>
> inline bool FlagHandler<s64>::Parse(const char *value) {
> const char *value_end;
> @@ -108,6 +151,12 @@ inline bool FlagHandler<s64>::Parse(const char *value) {
> return ok;
> }
>
> +template <>
> +inline bool FlagHandler<s64>::Format(char *buffer, uptr size) {
> + uptr num_symbols_should_write = internal_snprintf(buffer, size, "%lld", *t_);
> + return num_symbols_should_write < size;
> +}
> +
> class FlagParser {
> static const int kMaxFlags = 200;
> struct Flag {
> diff --git a/libsanitizer/sanitizer_common/sanitizer_flags.cpp b/libsanitizer/sanitizer_common/sanitizer_flags.cpp
> index 66a0a5579ed..684ee1e0b99 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_flags.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_flags.cpp
> @@ -75,11 +75,13 @@ void SubstituteForFlagValue(const char *s, char *out, uptr out_size) {
> class FlagHandlerInclude : public FlagHandlerBase {
> FlagParser *parser_;
> bool ignore_missing_;
> + const char *original_path_;
>
> public:
> explicit FlagHandlerInclude(FlagParser *parser, bool ignore_missing)
> - : parser_(parser), ignore_missing_(ignore_missing) {}
> + : parser_(parser), ignore_missing_(ignore_missing), original_path_("") {}
> bool Parse(const char *value) final {
> + original_path_ = value;
> if (internal_strchr(value, '%')) {
> char *buf = (char *)MmapOrDie(kMaxPathLength, "FlagHandlerInclude");
> SubstituteForFlagValue(value, buf, kMaxPathLength);
> @@ -89,6 +91,12 @@ class FlagHandlerInclude : public FlagHandlerBase {
> }
> return parser_->ParseFile(value, ignore_missing_);
> }
> + bool Format(char *buffer, uptr size) {
> + // Note `original_path_` isn't actually what's parsed due to `%`
> + // substitutions. Printing the substituted path would require holding onto
> + // mmap'ed memory.
> + return FormatString(buffer, size, original_path_);
> + }
> };
>
> void RegisterIncludeFlags(FlagParser *parser, CommonFlags *cf) {
> diff --git a/libsanitizer/sanitizer_common/sanitizer_freebsd.h b/libsanitizer/sanitizer_common/sanitizer_freebsd.h
> index 64cb21f1c3d..82b227eab6d 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_freebsd.h
> +++ b/libsanitizer/sanitizer_common/sanitizer_freebsd.h
> @@ -19,11 +19,11 @@
> // x86-64 FreeBSD 9.2 and older define 'ucontext_t' incorrectly in
> // 32-bit mode.
> #if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32)
> -# include <osreldate.h>
> -# if __FreeBSD_version <= 902001 // v9.2
> -# include <link.h>
> -# include <sys/param.h>
> -# include <ucontext.h>
> +#include <osreldate.h>
> +#if __FreeBSD_version <= 902001 // v9.2
> +#include <link.h>
> +#include <sys/param.h>
> +#include <ucontext.h>
>
> namespace __sanitizer {
>
> @@ -68,8 +68,8 @@ typedef struct __xmcontext {
> } xmcontext_t;
>
> typedef struct __xucontext {
> - sigset_t uc_sigmask;
> - xmcontext_t uc_mcontext;
> + sigset_t uc_sigmask;
> + xmcontext_t uc_mcontext;
>
> struct __ucontext *uc_link;
> stack_t uc_stack;
> @@ -122,15 +122,16 @@ struct xdl_phdr_info {
> void *dlpi_tls_data;
> };
>
> -typedef int (*__xdl_iterate_hdr_callback)(struct xdl_phdr_info*, size_t, void*);
> -typedef int xdl_iterate_phdr_t(__xdl_iterate_hdr_callback, void*);
> +typedef int (*__xdl_iterate_hdr_callback)(struct xdl_phdr_info *, size_t,
> + void *);
> +typedef int xdl_iterate_phdr_t(__xdl_iterate_hdr_callback, void *);
>
> #define xdl_iterate_phdr(callback, param) \
> - (((xdl_iterate_phdr_t*) dl_iterate_phdr)((callback), (param)))
> + (((xdl_iterate_phdr_t *)dl_iterate_phdr)((callback), (param)))
>
> } // namespace __sanitizer
>
> -# endif // __FreeBSD_version <= 902001
> +#endif // __FreeBSD_version <= 902001
> #endif // SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32)
>
> #endif // SANITIZER_FREEBSD_H
> diff --git a/libsanitizer/sanitizer_common/sanitizer_fuchsia.cpp b/libsanitizer/sanitizer_common/sanitizer_fuchsia.cpp
> index 6e2c6137f0c..6d1ad794677 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_fuchsia.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_fuchsia.cpp
> @@ -66,6 +66,10 @@ uptr internal_getpid() {
> return pid;
> }
>
> +int internal_dlinfo(void *handle, int request, void *p) {
> + UNIMPLEMENTED();
> +}
> +
> uptr GetThreadSelf() { return reinterpret_cast<uptr>(thrd_current()); }
>
> tid_t GetTid() { return GetThreadSelf(); }
> diff --git a/libsanitizer/sanitizer_common/sanitizer_fuchsia.h b/libsanitizer/sanitizer_common/sanitizer_fuchsia.h
> index 5a2ad32b411..96f9cde7ef1 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_fuchsia.h
> +++ b/libsanitizer/sanitizer_common/sanitizer_fuchsia.h
> @@ -18,12 +18,18 @@
> #include "sanitizer_common.h"
>
> #include <zircon/sanitizer.h>
> +#include <zircon/syscalls/object.h>
>
> namespace __sanitizer {
>
> extern uptr MainThreadStackBase, MainThreadStackSize;
> extern sanitizer_shadow_bounds_t ShadowBounds;
>
> +struct MemoryMappingLayoutData {
> + InternalMmapVector<zx_info_maps_t> data;
> + size_t current; // Current index into the vector.
> +};
> +
> } // namespace __sanitizer
>
> #endif // SANITIZER_FUCHSIA
> diff --git a/libsanitizer/sanitizer_common/sanitizer_interceptors_ioctl_netbsd.inc b/libsanitizer/sanitizer_common/sanitizer_interceptors_ioctl_netbsd.inc
> index 03ef7c1788c..576807ea3a6 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_interceptors_ioctl_netbsd.inc
> +++ b/libsanitizer/sanitizer_common/sanitizer_interceptors_ioctl_netbsd.inc
> @@ -24,7 +24,7 @@ struct ioctl_desc {
> const char *name;
> };
>
> -const unsigned ioctl_table_max = 1236;
> +const unsigned ioctl_table_max = 1238;
> static ioctl_desc ioctl_table[ioctl_table_max];
> static unsigned ioctl_table_size = 0;
>
> @@ -166,9 +166,6 @@ static void ioctl_table_fill() {
> _(FE_ENABLE_HIGH_LNB_VOLTAGE, READ, sizeof(int));
> _(FE_SET_FRONTEND_TUNE_MODE, READ, sizeof(unsigned int));
> _(FE_DISHNETWORK_SEND_LEGACY_CMD, READ, sizeof(unsigned long));
> - /* Entries from file: dev/filemon/filemon.h */
> - _(FILEMON_SET_FD, READWRITE, sizeof(int));
> - _(FILEMON_SET_PID, READWRITE, sizeof(int));
> /* Entries from file: dev/hdaudio/hdaudioio.h */
> _(HDAUDIO_FGRP_INFO, READWRITE, struct_plistref_sz);
> _(HDAUDIO_FGRP_GETCONFIG, READWRITE, struct_plistref_sz);
> @@ -449,9 +446,6 @@ static void ioctl_table_fill() {
> _(STICIO_STOPQ, NONE, 0);
> /* Entries from file: dev/usb/ukyopon.h */
> _(UKYOPON_IDENTIFY, WRITE, struct_ukyopon_identify_sz);
> - /* Entries from file: dev/usb/urio.h */
> - _(URIO_SEND_COMMAND, READWRITE, struct_urio_command_sz);
> - _(URIO_RECV_COMMAND, READWRITE, struct_urio_command_sz);
> /* Entries from file: dev/usb/usb.h */
> _(USB_REQUEST, READWRITE, struct_usb_ctl_request_sz);
> _(USB_SETDEBUG, READ, sizeof(int));
> @@ -653,6 +647,7 @@ static void ioctl_table_fill() {
> _(NVMM_IOC_MACHINE_CONFIGURE, READ, struct_nvmm_ioc_machine_configure_sz);
> _(NVMM_IOC_VCPU_CREATE, READ, struct_nvmm_ioc_vcpu_create_sz);
> _(NVMM_IOC_VCPU_DESTROY, READ, struct_nvmm_ioc_vcpu_destroy_sz);
> + _(NVMM_IOC_VCPU_CONFIGURE, READ, struct_nvmm_ioc_vcpu_configure_sz);
> _(NVMM_IOC_VCPU_SETSTATE, READ, struct_nvmm_ioc_vcpu_setstate_sz);
> _(NVMM_IOC_VCPU_GETSTATE, READ, struct_nvmm_ioc_vcpu_getstate_sz);
> _(NVMM_IOC_VCPU_INJECT, READ, struct_nvmm_ioc_vcpu_inject_sz);
> @@ -735,6 +730,7 @@ static void ioctl_table_fill() {
> _(IOC_NPF_SAVE, WRITE, struct_nvlist_ref_sz);
> _(IOC_NPF_RULE, READWRITE, struct_nvlist_ref_sz);
> _(IOC_NPF_CONN_LOOKUP, READWRITE, struct_nvlist_ref_sz);
> + _(IOC_NPF_TABLE_REPLACE, READWRITE, struct_nvlist_ref_sz);
> /* Entries from file: net/if_pppoe.h */
> _(PPPOESETPARMS, READ, struct_pppoediscparms_sz);
> _(PPPOEGETPARMS, READWRITE, struct_pppoediscparms_sz);
> @@ -1403,8 +1399,14 @@ static void ioctl_table_fill() {
> _(SNDCTL_DSP_SETRECVOL, READ, sizeof(unsigned int));
> _(SNDCTL_DSP_SKIP, NONE, 0);
> _(SNDCTL_DSP_SILENCE, NONE, 0);
> + /* Entries from file: dev/filemon/filemon.h (compat <= 9.99.26) */
> + _(FILEMON_SET_FD, READWRITE, sizeof(int));
> + _(FILEMON_SET_PID, READWRITE, sizeof(int));
> + /* Entries from file: dev/usb/urio.h (compat <= 9.99.43) */
> + _(URIO_SEND_COMMAND, READWRITE, struct_urio_command_sz);
> + _(URIO_RECV_COMMAND, READWRITE, struct_urio_command_sz);
> #undef _
> -} // NOLINT
> +} // NOLINT
>
> static bool ioctl_initialized = false;
>
> diff --git a/libsanitizer/sanitizer_common/sanitizer_interface_internal.h b/libsanitizer/sanitizer_common/sanitizer_interface_internal.h
> index c110eff130f..be8023e9e16 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_interface_internal.h
> +++ b/libsanitizer/sanitizer_common/sanitizer_interface_internal.h
> @@ -109,8 +109,10 @@ extern "C" {
> __sanitizer::u32*);
> SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
> void __sanitizer_cov_8bit_counters_init();
> - SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
> - void __sanitizer_cov_pcs_init();
> + SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void
> + __sanitizer_cov_bool_flag_init();
> + SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void
> + __sanitizer_cov_pcs_init();
> } // extern "C"
>
> #endif // SANITIZER_INTERFACE_INTERNAL_H
> diff --git a/libsanitizer/sanitizer_common/sanitizer_internal_defs.h b/libsanitizer/sanitizer_common/sanitizer_internal_defs.h
> index 00226305e07..d0ffc79b061 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_internal_defs.h
> +++ b/libsanitizer/sanitizer_common/sanitizer_internal_defs.h
> @@ -105,7 +105,7 @@
> // FIXME: do we have anything like this on Mac?
> #ifndef SANITIZER_CAN_USE_PREINIT_ARRAY
> #if ((SANITIZER_LINUX && !SANITIZER_ANDROID) || SANITIZER_OPENBSD || \
> - SANITIZER_FUCHSIA) && !defined(PIC)
> + SANITIZER_FUCHSIA || SANITIZER_NETBSD) && !defined(PIC)
> #define SANITIZER_CAN_USE_PREINIT_ARRAY 1
> // Before Solaris 11.4, .preinit_array is fully supported only with GNU ld.
> // FIXME: Check for those conditions.
> diff --git a/libsanitizer/sanitizer_common/sanitizer_libc.h b/libsanitizer/sanitizer_common/sanitizer_libc.h
> index 3d5db35d68b..ec0a6ded009 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_libc.h
> +++ b/libsanitizer/sanitizer_common/sanitizer_libc.h
> @@ -72,6 +72,8 @@ unsigned int internal_sleep(unsigned int seconds);
> uptr internal_getpid();
> uptr internal_getppid();
>
> +int internal_dlinfo(void *handle, int request, void *p);
> +
> // Threading
> uptr internal_sched_yield();
>
> diff --git a/libsanitizer/sanitizer_common/sanitizer_linux.cpp b/libsanitizer/sanitizer_common/sanitizer_linux.cpp
> index 3807a79b1cd..2168301fd69 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_linux.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_linux.cpp
> @@ -26,7 +26,7 @@
> #include "sanitizer_placement_new.h"
> #include "sanitizer_procmaps.h"
>
> -#if SANITIZER_LINUX
> +#if SANITIZER_LINUX && !SANITIZER_GO
> #include <asm/param.h>
> #endif
>
> @@ -166,7 +166,7 @@ namespace __sanitizer {
> #if !SANITIZER_SOLARIS && !SANITIZER_NETBSD
> #if !SANITIZER_S390 && !SANITIZER_OPENBSD
> uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd,
> - OFF_T offset) {
> + u64 offset) {
> #if SANITIZER_FREEBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS
> return internal_syscall(SYSCALL(mmap), (uptr)addr, length, prot, flags, fd,
> offset);
> @@ -552,13 +552,14 @@ const char *GetEnv(const char *name) {
> #endif
> }
>
> -#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD && !SANITIZER_OPENBSD
> +#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD && !SANITIZER_OPENBSD && \
> + !SANITIZER_GO
> extern "C" {
> SANITIZER_WEAK_ATTRIBUTE extern void *__libc_stack_end;
> }
> #endif
>
> -#if !SANITIZER_GO && !SANITIZER_FREEBSD && !SANITIZER_NETBSD && \
> +#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD && \
> !SANITIZER_OPENBSD
> static void ReadNullSepFileToArray(const char *path, char ***arr,
> int arr_size) {
> @@ -604,16 +605,21 @@ static void GetArgsAndEnv(char ***argv, char ***envp) {
> #else // SANITIZER_FREEBSD
> #if !SANITIZER_GO
> if (&__libc_stack_end) {
> -#endif // !SANITIZER_GO
> uptr* stack_end = (uptr*)__libc_stack_end;
> - int argc = *stack_end;
> + // Normally argc can be obtained from *stack_end, however, on ARM glibc's
> + // _start clobbers it:
> + // https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/arm/start.S;hb=refs/heads/release/2.31/master#l75
> + // Do not special-case ARM and infer argc from argv everywhere.
> + int argc = 0;
> + while (stack_end[argc + 1]) argc++;
> *argv = (char**)(stack_end + 1);
> *envp = (char**)(stack_end + argc + 2);
> -#if !SANITIZER_GO
> } else {
> +#endif // !SANITIZER_GO
> static const int kMaxArgv = 2000, kMaxEnvp = 2000;
> ReadNullSepFileToArray("/proc/self/cmdline", argv, kMaxArgv);
> ReadNullSepFileToArray("/proc/self/environ", envp, kMaxEnvp);
> +#if !SANITIZER_GO
> }
> #endif // !SANITIZER_GO
> #endif // SANITIZER_FREEBSD
> @@ -735,6 +741,14 @@ uptr internal_getppid() {
> return internal_syscall(SYSCALL(getppid));
> }
>
> +int internal_dlinfo(void *handle, int request, void *p) {
> +#if SANITIZER_FREEBSD
> + return dlinfo(handle, request, p);
> +#else
> + UNIMPLEMENTED();
> +#endif
> +}
> +
> uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count) {
> #if SANITIZER_FREEBSD
> return internal_syscall(SYSCALL(getdirentries), fd, (uptr)dirp, count, NULL);
> @@ -1006,9 +1020,8 @@ static uptr GetKernelAreaSize() {
> // is modified (e.g. under schroot) so check this as well.
> struct utsname uname_info;
> int pers = personality(0xffffffffUL);
> - if (!(pers & PER_MASK)
> - && uname(&uname_info) == 0
> - && internal_strstr(uname_info.machine, "64"))
> + if (!(pers & PER_MASK) && internal_uname(&uname_info) == 0 &&
> + internal_strstr(uname_info.machine, "64"))
> return 0;
> #endif // SANITIZER_ANDROID
>
> @@ -1063,7 +1076,8 @@ uptr GetMaxUserVirtualAddress() {
>
> #if !SANITIZER_ANDROID
> uptr GetPageSize() {
> -#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__i386__))
> +#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__i386__)) && \
> + defined(EXEC_PAGESIZE)
> return EXEC_PAGESIZE;
> #elif SANITIZER_FREEBSD || SANITIZER_NETBSD
> // Use sysctl as sysconf can trigger interceptors internally.
> @@ -1619,6 +1633,12 @@ uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
> }
> #endif // defined(__x86_64__) && SANITIZER_LINUX
>
> +#if SANITIZER_LINUX
> +int internal_uname(struct utsname *buf) {
> + return internal_syscall(SYSCALL(uname), buf);
> +}
> +#endif
> +
> #if SANITIZER_ANDROID
> #if __ANDROID_API__ < 21
> extern "C" __attribute__((weak)) int dl_iterate_phdr(
> @@ -1701,7 +1721,7 @@ HandleSignalMode GetHandleSignalMode(int signum) {
> }
>
> #if !SANITIZER_GO
> -void *internal_start_thread(void(*func)(void *arg), void *arg) {
> +void *internal_start_thread(void *(*func)(void *arg), void *arg) {
> // Start the thread with signals blocked, otherwise it can steal user signals.
> __sanitizer_sigset_t set, old;
> internal_sigfillset(&set);
> @@ -1712,7 +1732,7 @@ void *internal_start_thread(void(*func)(void *arg), void *arg) {
> #endif
> internal_sigprocmask(SIG_SETMASK, &set, &old);
> void *th;
> - real_pthread_create(&th, nullptr, (void*(*)(void *arg))func, arg);
> + real_pthread_create(&th, nullptr, func, arg);
> internal_sigprocmask(SIG_SETMASK, &old, nullptr);
> return th;
> }
> @@ -1721,7 +1741,7 @@ void internal_join_thread(void *th) {
> real_pthread_join(th, nullptr);
> }
> #else
> -void *internal_start_thread(void (*func)(void *), void *arg) { return 0; }
> +void *internal_start_thread(void *(*func)(void *), void *arg) { return 0; }
>
> void internal_join_thread(void *th) {}
> #endif
> @@ -1846,6 +1866,105 @@ SignalContext::WriteFlag SignalContext::GetWriteFlag() const {
> #endif
> u32 instr = *(u32 *)pc;
> return (instr >> 21) & 1 ? WRITE: READ;
> +#elif defined(__riscv)
> + unsigned long pc = ucontext->uc_mcontext.__gregs[REG_PC];
> + unsigned faulty_instruction = *(uint16_t *)pc;
> +
> +#if defined(__riscv_compressed)
> + if ((faulty_instruction & 0x3) != 0x3) { // it's a compressed instruction
> + // set op_bits to the instruction bits [1, 0, 15, 14, 13]
> + unsigned op_bits =
> + ((faulty_instruction & 0x3) << 3) | (faulty_instruction >> 13);
> + unsigned rd = faulty_instruction & 0xF80; // bits 7-11, inclusive
> + switch (op_bits) {
> + case 0b10'010: // c.lwsp (rd != x0)
> +#if __riscv_xlen == 64
> + case 0b10'011: // c.ldsp (rd != x0)
> +#endif
> + return rd ? SignalContext::READ : SignalContext::UNKNOWN;
> + case 0b00'010: // c.lw
> +#if __riscv_flen >= 32 && __riscv_xlen == 32
> + case 0b10'011: // c.flwsp
> +#endif
> +#if __riscv_flen >= 32 || __riscv_xlen == 64
> + case 0b00'011: // c.flw / c.ld
> +#endif
> +#if __riscv_flen == 64
> + case 0b00'001: // c.fld
> + case 0b10'001: // c.fldsp
> +#endif
> + return SignalContext::READ;
> + case 0b00'110: // c.sw
> + case 0b10'110: // c.swsp
> +#if __riscv_flen >= 32 || __riscv_xlen == 64
> + case 0b00'111: // c.fsw / c.sd
> + case 0b10'111: // c.fswsp / c.sdsp
> +#endif
> +#if __riscv_flen == 64
> + case 0b00'101: // c.fsd
> + case 0b10'101: // c.fsdsp
> +#endif
> + return SignalContext::WRITE;
> + default:
> + return SignalContext::UNKNOWN;
> + }
> + }
> +#endif
> +
> + unsigned opcode = faulty_instruction & 0x7f; // lower 7 bits
> + unsigned funct3 = (faulty_instruction >> 12) & 0x7; // bits 12-14, inclusive
> + switch (opcode) {
> + case 0b0000011: // loads
> + switch (funct3) {
> + case 0b000: // lb
> + case 0b001: // lh
> + case 0b010: // lw
> +#if __riscv_xlen == 64
> + case 0b011: // ld
> +#endif
> + case 0b100: // lbu
> + case 0b101: // lhu
> + return SignalContext::READ;
> + default:
> + return SignalContext::UNKNOWN;
> + }
> + case 0b0100011: // stores
> + switch (funct3) {
> + case 0b000: // sb
> + case 0b001: // sh
> + case 0b010: // sw
> +#if __riscv_xlen == 64
> + case 0b011: // sd
> +#endif
> + return SignalContext::WRITE;
> + default:
> + return SignalContext::UNKNOWN;
> + }
> +#if __riscv_flen >= 32
> + case 0b0000111: // floating-point loads
> + switch (funct3) {
> + case 0b010: // flw
> +#if __riscv_flen == 64
> + case 0b011: // fld
> +#endif
> + return SignalContext::READ;
> + default:
> + return SignalContext::UNKNOWN;
> + }
> + case 0b0100111: // floating-point stores
> + switch (funct3) {
> + case 0b010: // fsw
> +#if __riscv_flen == 64
> + case 0b011: // fsd
> +#endif
> + return SignalContext::WRITE;
> + default:
> + return SignalContext::UNKNOWN;
> + }
> +#endif
> + default:
> + return SignalContext::UNKNOWN;
> + }
> #else
> (void)ucontext;
> return UNKNOWN; // FIXME: Implement.
> @@ -2011,7 +2130,9 @@ void CheckASLR() {
> }
>
> if (UNLIKELY(paxflags & CTL_PROC_PAXFLAGS_ASLR)) {
> - Printf("This sanitizer is not compatible with enabled ASLR\n");
> + Printf("This sanitizer is not compatible with enabled ASLR.\n"
> + "To disable ASLR, please run \"paxctl +a %s\" and try again.\n",
> + GetArgv()[0]);
> Die();
> }
> #elif SANITIZER_PPC64V2
> diff --git a/libsanitizer/sanitizer_common/sanitizer_linux.h b/libsanitizer/sanitizer_common/sanitizer_linux.h
> index c28347ad963..c162d1ca5d2 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_linux.h
> +++ b/libsanitizer/sanitizer_common/sanitizer_linux.h
> @@ -25,6 +25,7 @@
> #include "sanitizer_posix.h"
>
> struct link_map; // Opaque type returned by dlopen().
> +struct utsname;
>
> namespace __sanitizer {
> // Dirent structure for getdents(). Note that this structure is different from
> @@ -65,6 +66,7 @@ void internal_sigdelset(__sanitizer_sigset_t *set, int signum);
> uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
> int *parent_tidptr, void *newtls, int *child_tidptr);
> #endif
> +int internal_uname(struct utsname *buf);
> #elif SANITIZER_FREEBSD
> void internal_sigdelset(__sanitizer_sigset_t *set, int signum);
> #elif SANITIZER_NETBSD
> diff --git a/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp
> index e09d568d802..4d17c9686e4 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp
> @@ -35,6 +35,10 @@
> #include <sys/resource.h>
> #include <syslog.h>
>
> +#if !defined(ElfW)
> +#define ElfW(type) Elf_##type
> +#endif
> +
> #if SANITIZER_FREEBSD
> #include <pthread_np.h>
> #include <osreldate.h>
> @@ -50,6 +54,7 @@
> #if SANITIZER_NETBSD
> #include <sys/sysctl.h>
> #include <sys/tls.h>
> +#include <lwp.h>
> #endif
>
> #if SANITIZER_SOLARIS
> @@ -399,13 +404,7 @@ uptr ThreadSelf() {
>
> #if SANITIZER_NETBSD
> static struct tls_tcb * ThreadSelfTlsTcb() {
> - struct tls_tcb * tcb;
> -# ifdef __HAVE___LWP_GETTCB_FAST
> - tcb = (struct tls_tcb *)__lwp_gettcb_fast();
> -# elif defined(__HAVE___LWP_GETPRIVATE_FAST)
> - tcb = (struct tls_tcb *)__lwp_getprivate_fast();
> -# endif
> - return tcb;
> + return (struct tls_tcb *)_lwp_getprivate();
> }
>
> uptr ThreadSelf() {
> @@ -698,13 +697,9 @@ u32 GetNumberOfCPUs() {
> #elif SANITIZER_SOLARIS
> return sysconf(_SC_NPROCESSORS_ONLN);
> #else
> -#if defined(CPU_COUNT)
> cpu_set_t CPUs;
> CHECK_EQ(sched_getaffinity(0, sizeof(cpu_set_t), &CPUs), 0);
> return CPU_COUNT(&CPUs);
> -#else
> - return 1;
> -#endif
> #endif
> }
>
> diff --git a/libsanitizer/sanitizer_common/sanitizer_linux_s390.cpp b/libsanitizer/sanitizer_common/sanitizer_linux_s390.cpp
> index 41e187eaf8d..bb2f5b5f9f7 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_linux_s390.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_linux_s390.cpp
> @@ -15,19 +15,20 @@
>
> #if SANITIZER_LINUX && SANITIZER_S390
>
> -#include "sanitizer_libc.h"
> -#include "sanitizer_linux.h"
> -
> +#include <dlfcn.h>
> #include <errno.h>
> #include <sys/syscall.h>
> #include <sys/utsname.h>
> #include <unistd.h>
>
> +#include "sanitizer_libc.h"
> +#include "sanitizer_linux.h"
> +
> namespace __sanitizer {
>
> // --------------- sanitizer_libc.h
> uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd,
> - OFF_T offset) {
> + u64 offset) {
> struct s390_mmap_params {
> unsigned long addr;
> unsigned long length;
> @@ -123,7 +124,7 @@ static bool FixedCVE_2016_2143() {
> struct utsname buf;
> unsigned int major, minor, patch = 0;
> // This should never fail, but just in case...
> - if (uname(&buf))
> + if (internal_uname(&buf))
> return false;
> const char *ptr = buf.release;
> major = internal_simple_strtoll(ptr, &ptr, 10);
> diff --git a/libsanitizer/sanitizer_common/sanitizer_mac.cpp b/libsanitizer/sanitizer_common/sanitizer_mac.cpp
> index b971ad058e9..7550545ea6f 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_mac.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_mac.cpp
> @@ -30,6 +30,7 @@
> #include "sanitizer_placement_new.h"
> #include "sanitizer_platform_limits_posix.h"
> #include "sanitizer_procmaps.h"
> +#include "sanitizer_ptrauth.h"
>
> #if !SANITIZER_IOS
> #include <crt_externs.h> // for _NSGetEnviron
> @@ -37,7 +38,7 @@
> extern char **environ;
> #endif
>
> -#if defined(__has_include) && __has_include(<os/trace.h>) && defined(__BLOCKS__)
> +#if defined(__has_include) && __has_include(<os/trace.h>)
> #define SANITIZER_OS_TRACE 1
> #include <os/trace.h>
> #else
> @@ -208,6 +209,10 @@ uptr internal_getpid() {
> return getpid();
> }
>
> +int internal_dlinfo(void *handle, int request, void *p) {
> + UNIMPLEMENTED();
> +}
> +
> int internal_sigaction(int signum, const void *act, void *oldact) {
> return sigaction(signum,
> (const struct sigaction *)act, (struct sigaction *)oldact);
> @@ -242,7 +247,8 @@ int internal_sysctlbyname(const char *sname, void *oldp, uptr *oldlenp,
> (size_t)newlen);
> }
>
> -static fd_t internal_spawn_impl(const char *argv[], pid_t *pid) {
> +static fd_t internal_spawn_impl(const char *argv[], const char *envp[],
> + pid_t *pid) {
> fd_t master_fd = kInvalidFd;
> fd_t slave_fd = kInvalidFd;
>
> @@ -298,8 +304,8 @@ static fd_t internal_spawn_impl(const char *argv[], pid_t *pid) {
>
> // posix_spawn
> char **argv_casted = const_cast<char **>(argv);
> - char **env = GetEnviron();
> - res = posix_spawn(pid, argv[0], &acts, &attrs, argv_casted, env);
> + char **envp_casted = const_cast<char **>(envp);
> + res = posix_spawn(pid, argv[0], &acts, &attrs, argv_casted, envp_casted);
> if (res != 0) return kInvalidFd;
>
> // Disable echo in the new terminal, disable CR.
> @@ -316,7 +322,7 @@ static fd_t internal_spawn_impl(const char *argv[], pid_t *pid) {
> return fd;
> }
>
> -fd_t internal_spawn(const char *argv[], pid_t *pid) {
> +fd_t internal_spawn(const char *argv[], const char *envp[], pid_t *pid) {
> // The client program may close its stdin and/or stdout and/or stderr thus
> // allowing open/posix_openpt to reuse file descriptors 0, 1 or 2. In this
> // case the communication is broken if either the parent or the child tries to
> @@ -331,7 +337,7 @@ fd_t internal_spawn(const char *argv[], pid_t *pid) {
> break;
> }
>
> - fd_t fd = internal_spawn_impl(argv, pid);
> + fd_t fd = internal_spawn_impl(argv, envp, pid);
>
> for (; count > 0; count--) {
> internal_close(low_fds[count]);
> @@ -623,19 +629,13 @@ MacosVersion GetMacosVersionInternal() {
> if (*p != '.') return MACOS_VERSION_UNKNOWN;
>
> switch (major) {
> - case 9: return MACOS_VERSION_LEOPARD;
> - case 10: return MACOS_VERSION_SNOW_LEOPARD;
> case 11: return MACOS_VERSION_LION;
> case 12: return MACOS_VERSION_MOUNTAIN_LION;
> case 13: return MACOS_VERSION_MAVERICKS;
> case 14: return MACOS_VERSION_YOSEMITE;
> case 15: return MACOS_VERSION_EL_CAPITAN;
> case 16: return MACOS_VERSION_SIERRA;
> - case 17:
> - // Not a typo, 17.5 Darwin Kernel Version maps to High Sierra 10.13.4.
> - if (minor >= 5)
> - return MACOS_VERSION_HIGH_SIERRA_DOT_RELEASE_4;
> - return MACOS_VERSION_HIGH_SIERRA;
> + case 17: return MACOS_VERSION_HIGH_SIERRA;
> case 18: return MACOS_VERSION_MOJAVE;
> case 19: return MACOS_VERSION_CATALINA;
> default:
> @@ -656,13 +656,21 @@ MacosVersion GetMacosVersion() {
> return result;
> }
>
> -bool PlatformHasDifferentMemcpyAndMemmove() {
> - // On OS X 10.7 memcpy() and memmove() are both resolved
> - // into memmove$VARIANT$sse42.
> - // See also https://github.com/google/sanitizers/issues/34.
> - // TODO(glider): need to check dynamically that memcpy() and memmove() are
> - // actually the same function.
> - return GetMacosVersion() == MACOS_VERSION_SNOW_LEOPARD;
> +DarwinKernelVersion GetDarwinKernelVersion() {
> + char buf[100];
> + size_t len = sizeof(buf);
> + int res = internal_sysctlbyname("kern.osrelease", buf, &len, nullptr, 0);
> + CHECK_EQ(res, 0);
> +
> + // Format: <major>.<minor>.<patch>\0
> + CHECK_GE(len, 6);
> + const char *p = buf;
> + u16 major = internal_simple_strtoll(p, &p, /*base=*/10);
> + CHECK_EQ(*p, '.');
> + p += 1;
> + u16 minor = internal_simple_strtoll(p, &p, /*base=*/10);
> +
> + return DarwinKernelVersion(major, minor);
> }
>
> uptr GetRSS() {
> @@ -677,13 +685,13 @@ uptr GetRSS() {
> return info.resident_size;
> }
>
> -void *internal_start_thread(void(*func)(void *arg), void *arg) {
> +void *internal_start_thread(void *(*func)(void *arg), void *arg) {
> // Start the thread with signals blocked, otherwise it can steal user signals.
> __sanitizer_sigset_t set, old;
> internal_sigfillset(&set);
> internal_sigprocmask(SIG_SETMASK, &set, &old);
> pthread_t th;
> - pthread_create(&th, 0, (void*(*)(void *arg))func, arg);
> + pthread_create(&th, 0, func, arg);
> internal_sigprocmask(SIG_SETMASK, &old, 0);
> return th;
> }
> @@ -760,16 +768,24 @@ bool SignalContext::IsTrueFaultingAddress() const {
> return si->si_signo == SIGSEGV && si->si_code != 0;
> }
>
> +#if defined(__aarch64__) && defined(arm_thread_state64_get_sp)
> + #define AARCH64_GET_REG(r) \
> + (uptr)ptrauth_strip( \
> + (void *)arm_thread_state64_get_##r(ucontext->uc_mcontext->__ss), 0)
> +#else
> + #define AARCH64_GET_REG(r) ucontext->uc_mcontext->__ss.__##r
> +#endif
> +
> static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
> ucontext_t *ucontext = (ucontext_t*)context;
> # if defined(__aarch64__)
> - *pc = ucontext->uc_mcontext->__ss.__pc;
> + *pc = AARCH64_GET_REG(pc);
> # if defined(__IPHONE_8_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_8_0
> - *bp = ucontext->uc_mcontext->__ss.__fp;
> + *bp = AARCH64_GET_REG(fp);
> # else
> - *bp = ucontext->uc_mcontext->__ss.__lr;
> + *bp = AARCH64_GET_REG(lr);
> # endif
> - *sp = ucontext->uc_mcontext->__ss.__sp;
> + *sp = AARCH64_GET_REG(sp);
> # elif defined(__x86_64__)
> *pc = ucontext->uc_mcontext->__ss.__rip;
> *bp = ucontext->uc_mcontext->__ss.__rbp;
> @@ -787,13 +803,16 @@ static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
> # endif
> }
>
> -void SignalContext::InitPcSpBp() { GetPcSpBp(context, &pc, &sp, &bp); }
> +void SignalContext::InitPcSpBp() {
> + addr = (uptr)ptrauth_strip((void *)addr, 0);
> + GetPcSpBp(context, &pc, &sp, &bp);
> +}
>
> void InitializePlatformEarly() {
> - // Only use xnu_fast_mmap when on x86_64 and the OS supports it.
> + // Only use xnu_fast_mmap when on x86_64 and the kernel supports it.
> use_xnu_fast_mmap =
> #if defined(__x86_64__)
> - GetMacosVersion() >= MACOS_VERSION_HIGH_SIERRA_DOT_RELEASE_4;
> + GetDarwinKernelVersion() >= DarwinKernelVersion(17, 5);
> #else
> false;
> #endif
> @@ -1123,6 +1142,8 @@ void SignalContext::DumpAllRegisters(void *context) {
> ucontext_t *ucontext = (ucontext_t*)context;
> # define DUMPREG64(r) \
> Printf("%s = 0x%016llx ", #r, ucontext->uc_mcontext->__ss.__ ## r);
> +# define DUMPREGA64(r) \
> + Printf(" %s = 0x%016llx ", #r, AARCH64_GET_REG(r));
> # define DUMPREG32(r) \
> Printf("%s = 0x%08x ", #r, ucontext->uc_mcontext->__ss.__ ## r);
> # define DUMPREG_(r) Printf(" "); DUMPREG(r);
> @@ -1148,7 +1169,7 @@ void SignalContext::DumpAllRegisters(void *context) {
> DUMPREG(x[16]); DUMPREG(x[17]); DUMPREG(x[18]); DUMPREG(x[19]); Printf("\n");
> DUMPREG(x[20]); DUMPREG(x[21]); DUMPREG(x[22]); DUMPREG(x[23]); Printf("\n");
> DUMPREG(x[24]); DUMPREG(x[25]); DUMPREG(x[26]); DUMPREG(x[27]); Printf("\n");
> - DUMPREG(x[28]); DUMPREG___(fp); DUMPREG___(lr); DUMPREG___(sp); Printf("\n");
> + DUMPREG(x[28]); DUMPREGA64(fp); DUMPREGA64(lr); DUMPREGA64(sp); Printf("\n");
> # elif defined(__arm__)
> # define DUMPREG(r) DUMPREG32(r)
> DUMPREG_(r[0]); DUMPREG_(r[1]); DUMPREG_(r[2]); DUMPREG_(r[3]); Printf("\n");
> diff --git a/libsanitizer/sanitizer_common/sanitizer_mac.h b/libsanitizer/sanitizer_common/sanitizer_mac.h
> index 2257883084e..34dc2c05dcf 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_mac.h
> +++ b/libsanitizer/sanitizer_common/sanitizer_mac.h
> @@ -33,22 +33,35 @@ struct MemoryMappingLayoutData {
> enum MacosVersion {
> MACOS_VERSION_UNINITIALIZED = 0,
> MACOS_VERSION_UNKNOWN,
> - MACOS_VERSION_LEOPARD,
> - MACOS_VERSION_SNOW_LEOPARD,
> - MACOS_VERSION_LION,
> + MACOS_VERSION_LION, // macOS 10.7; oldest currently supported
> MACOS_VERSION_MOUNTAIN_LION,
> MACOS_VERSION_MAVERICKS,
> MACOS_VERSION_YOSEMITE,
> MACOS_VERSION_EL_CAPITAN,
> MACOS_VERSION_SIERRA,
> MACOS_VERSION_HIGH_SIERRA,
> - MACOS_VERSION_HIGH_SIERRA_DOT_RELEASE_4,
> MACOS_VERSION_MOJAVE,
> MACOS_VERSION_CATALINA,
> MACOS_VERSION_UNKNOWN_NEWER
> };
>
> +struct DarwinKernelVersion {
> + u16 major;
> + u16 minor;
> +
> + DarwinKernelVersion(u16 major, u16 minor) : major(major), minor(minor) {}
> +
> + bool operator==(const DarwinKernelVersion &other) const {
> + return major == other.major && minor == other.minor;
> + }
> + bool operator>=(const DarwinKernelVersion &other) const {
> + return major >= other.major ||
> + (major == other.major && minor >= other.minor);
> + }
> +};
> +
> MacosVersion GetMacosVersion();
> +DarwinKernelVersion GetDarwinKernelVersion();
>
> char **GetEnviron();
>
> diff --git a/libsanitizer/sanitizer_common/sanitizer_malloc_mac.inc b/libsanitizer/sanitizer_common/sanitizer_malloc_mac.inc
> index 11adbe5c25b..647bcdfe105 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_malloc_mac.inc
> +++ b/libsanitizer/sanitizer_common/sanitizer_malloc_mac.inc
> @@ -61,12 +61,10 @@ INTERCEPTOR(malloc_zone_t *, malloc_create_zone,
> malloc_zone_t *new_zone = (malloc_zone_t *)p;
> internal_memcpy(new_zone, &sanitizer_zone, sizeof(sanitizer_zone));
> new_zone->zone_name = NULL; // The name will be changed anyway.
> - if (GetMacosVersion() >= MACOS_VERSION_LION) {
> - // Prevent the client app from overwriting the zone contents.
> - // Library functions that need to modify the zone will set PROT_WRITE on it.
> - // This matches the behavior of malloc_create_zone() on OSX 10.7 and higher.
> - mprotect(new_zone, allocated_size, PROT_READ);
> - }
> + // Prevent the client app from overwriting the zone contents.
> + // Library functions that need to modify the zone will set PROT_WRITE on it.
> + // This matches the behavior of malloc_create_zone() on OSX 10.7 and higher.
> + mprotect(new_zone, allocated_size, PROT_READ);
> // We're explicitly *NOT* registering the zone.
> return new_zone;
> }
> @@ -75,11 +73,9 @@ INTERCEPTOR(void, malloc_destroy_zone, malloc_zone_t *zone) {
> COMMON_MALLOC_ENTER();
> // We don't need to do anything here. We're not registering new zones, so we
> // don't to unregister. Just un-mprotect and free() the zone.
> - if (GetMacosVersion() >= MACOS_VERSION_LION) {
> - uptr page_size = GetPageSizeCached();
> - uptr allocated_size = RoundUpTo(sizeof(sanitizer_zone), page_size);
> - mprotect(zone, allocated_size, PROT_READ | PROT_WRITE);
> - }
> + uptr page_size = GetPageSizeCached();
> + uptr allocated_size = RoundUpTo(sizeof(sanitizer_zone), page_size);
> + mprotect(zone, allocated_size, PROT_READ | PROT_WRITE);
> if (zone->zone_name) {
> COMMON_MALLOC_FREE((void *)zone->zone_name);
> }
> diff --git a/libsanitizer/sanitizer_common/sanitizer_netbsd.cpp b/libsanitizer/sanitizer_common/sanitizer_netbsd.cpp
> index 4e74f6a3b51..d9aff51d8ae 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_netbsd.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_netbsd.cpp
> @@ -95,7 +95,7 @@ static void *GetRealLibcAddress(const char *symbol) {
>
> // --------------- sanitizer_libc.h
> uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd,
> - OFF_T offset) {
> + u64 offset) {
> CHECK(&__mmap);
> return (uptr)__mmap(addr, length, prot, flags, fd, 0, offset);
> }
> @@ -265,6 +265,11 @@ uptr internal_getppid() {
> return _REAL(getppid);
> }
>
> +int internal_dlinfo(void *handle, int request, void *p) {
> + DEFINE__REAL(int, dlinfo, void *a, int b, void *c);
> + return _REAL(dlinfo, handle, request, p);
> +}
> +
> uptr internal_getdents(fd_t fd, void *dirp, unsigned int count) {
> DEFINE__REAL(int, __getdents30, int a, void *b, size_t c);
> return _REAL(__getdents30, fd, dirp, count);
> diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h b/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h
> index 61a6b82ef81..9dd6d285f59 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h
> +++ b/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h
> @@ -90,6 +90,24 @@
> # define SI_IOS 0
> #endif
>
> +#if SANITIZER_IOSSIM
> +# define SI_IOSSIM 1
> +#else
> +# define SI_IOSSIM 0
> +#endif
> +
> +#if SANITIZER_WATCHOS
> +# define SI_WATCHOS 1
> +#else
> +# define SI_WATCHOS 0
> +#endif
> +
> +#if SANITIZER_TVOS
> +# define SI_TVOS 1
> +#else
> +# define SI_TVOS 0
> +#endif
> +
> #if SANITIZER_FUCHSIA
> # define SI_NOT_FUCHSIA 0
> #else
> @@ -575,5 +593,11 @@
> #define SANITIZER_INTERCEPT_ATEXIT SI_NETBSD
> #define SANITIZER_INTERCEPT_PTHREAD_ATFORK SI_NETBSD
> #define SANITIZER_INTERCEPT_GETENTROPY SI_FREEBSD
> +#define SANITIZER_INTERCEPT_QSORT \
> + (SI_POSIX && !SI_IOSSIM && !SI_WATCHOS && !SI_TVOS && !SI_ANDROID)
> +#define SANITIZER_INTERCEPT_QSORT_R (SI_LINUX && !SI_ANDROID)
> +#define SANITIZER_INTERCEPT_SIGALTSTACK SI_POSIX
> +#define SANITIZER_INTERCEPT_UNAME (SI_POSIX && !SI_FREEBSD)
> +#define SANITIZER_INTERCEPT___XUNAME SI_FREEBSD
>
> #endif // #ifndef SANITIZER_PLATFORM_INTERCEPTORS_H
> diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.cpp b/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.cpp
> index 2d1bb1a12da..dcc6c71c07d 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.cpp
> @@ -15,342 +15,348 @@
>
> #if SANITIZER_FREEBSD
>
> +#include <sys/capsicum.h>
> +#include <sys/consio.h>
> +#include <sys/filio.h>
> +#include <sys/ipc.h>
> +#include <sys/kbio.h>
> +#include <sys/link_elf.h>
> +#include <sys/mman.h>
> +#include <sys/mount.h>
> +#include <sys/mqueue.h>
> +#include <sys/msg.h>
> +#include <sys/mtio.h>
> +#include <sys/ptrace.h>
> +#include <sys/resource.h>
> +#include <sys/signal.h>
> +#include <sys/socket.h>
> +#include <sys/sockio.h>
> +#include <sys/soundcard.h>
> +#include <sys/stat.h>
> +#include <sys/statvfs.h>
> +#include <sys/time.h>
> +#include <sys/timeb.h>
> +#include <sys/times.h>
> +#include <sys/timespec.h>
> +#include <sys/types.h>
> +#include <sys/ucontext.h>
> +#include <sys/utsname.h>
> +//
> #include <arpa/inet.h>
> +#include <net/ethernet.h>
> +#include <net/if.h>
> +#include <net/ppp_defs.h>
> +#include <net/route.h>
> +#include <netdb.h>
> +#include <netinet/in.h>
> +#include <netinet/ip_mroute.h>
> +//
> #include <dirent.h>
> -#include <fts.h>
> +#include <dlfcn.h>
> #include <fstab.h>
> +#include <fts.h>
> +#include <glob.h>
> #include <grp.h>
> +#include <ifaddrs.h>
> #include <limits.h>
> -#include <net/if.h>
> -#include <netdb.h>
> #include <poll.h>
> #include <pthread.h>
> #include <pwd.h>
> #include <regex.h>
> +#include <semaphore.h>
> #include <signal.h>
> #include <stddef.h>
> -#include <sys/mman.h>
> -#include <sys/capsicum.h>
> -#include <sys/resource.h>
> -#include <sys/stat.h>
> -#include <sys/time.h>
> -#include <sys/times.h>
> -#include <sys/types.h>
> -#include <sys/utsname.h>
> -#include <termios.h>
> -#include <time.h>
> -
> -#include <net/route.h>
> -#include <sys/mount.h>
> -#include <sys/sockio.h>
> -#include <sys/socket.h>
> -#include <sys/filio.h>
> -#include <sys/signal.h>
> -#include <sys/timespec.h>
> -#include <sys/timeb.h>
> -#include <sys/mqueue.h>
> -#include <sys/msg.h>
> -#include <sys/ipc.h>
> -#include <sys/msg.h>
> -#include <sys/statvfs.h>
> -#include <sys/soundcard.h>
> -#include <sys/mtio.h>
> -#include <sys/consio.h>
> -#include <sys/kbio.h>
> -#include <sys/link_elf.h>
> -#include <netinet/ip_mroute.h>
> -#include <netinet/in.h>
> -#include <net/ethernet.h>
> -#include <net/ppp_defs.h>
> -#include <glob.h>
> #include <stdio.h>
> #include <stringlist.h>
> #include <term.h>
> +#include <termios.h>
> +#include <time.h>
> +#include <utime.h>
> #include <utmpx.h>
> -#include <wchar.h>
> #include <vis.h>
> +#include <wchar.h>
> +#include <wordexp.h>
>
> #define _KERNEL // to declare 'shminfo' structure
> -# include <sys/shm.h>
> +#include <sys/shm.h>
> #undef _KERNEL
>
> #undef INLINE // to avoid clashes with sanitizers' definitions
>
> #undef IOC_DIRMASK
>
> -# include <utime.h>
> -# include <sys/ptrace.h>
> -# include <semaphore.h>
> -
> -#include <ifaddrs.h>
> -#include <sys/ucontext.h>
> -#include <wordexp.h>
> -
> // Include these after system headers to avoid name clashes and ambiguities.
> #include "sanitizer_internal_defs.h"
> +#include "sanitizer_libc.h"
> #include "sanitizer_platform_limits_freebsd.h"
>
> namespace __sanitizer {
> - unsigned struct_cap_rights_sz = sizeof(cap_rights_t);
> - unsigned struct_utsname_sz = sizeof(struct utsname);
> - unsigned struct_stat_sz = sizeof(struct stat);
> - unsigned struct_rusage_sz = sizeof(struct rusage);
> - unsigned struct_tm_sz = sizeof(struct tm);
> - unsigned struct_passwd_sz = sizeof(struct passwd);
> - unsigned struct_group_sz = sizeof(struct group);
> - unsigned siginfo_t_sz = sizeof(siginfo_t);
> - unsigned struct_sigaction_sz = sizeof(struct sigaction);
> - unsigned struct_itimerval_sz = sizeof(struct itimerval);
> - unsigned pthread_t_sz = sizeof(pthread_t);
> - unsigned pthread_mutex_t_sz = sizeof(pthread_mutex_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);
> - unsigned gid_t_sz = sizeof(gid_t);
> - unsigned fpos_t_sz = sizeof(fpos_t);
> - unsigned mbstate_t_sz = sizeof(mbstate_t);
> - unsigned sigset_t_sz = sizeof(sigset_t);
> - unsigned struct_timezone_sz = sizeof(struct timezone);
> - 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);
> - unsigned struct_sockaddr_sz = sizeof(struct sockaddr);
> - unsigned ucontext_t_sz = sizeof(ucontext_t);
> - unsigned struct_rlimit_sz = sizeof(struct rlimit);
> - unsigned struct_timespec_sz = sizeof(struct timespec);
> - unsigned struct_utimbuf_sz = sizeof(struct utimbuf);
> - unsigned struct_itimerspec_sz = sizeof(struct itimerspec);
> - unsigned struct_timeb_sz = sizeof(struct timeb);
> - unsigned struct_msqid_ds_sz = sizeof(struct msqid_ds);
> - unsigned struct_mq_attr_sz = sizeof(struct mq_attr);
> - unsigned struct_statvfs_sz = sizeof(struct statvfs);
> - unsigned struct_shminfo_sz = sizeof(struct shminfo);
> - unsigned struct_shm_info_sz = sizeof(struct shm_info);
> - unsigned struct_regmatch_sz = sizeof(regmatch_t);
> - unsigned struct_regex_sz = sizeof(regex_t);
> - unsigned struct_fstab_sz = sizeof(struct fstab);
> - unsigned struct_FTS_sz = sizeof(FTS);
> - unsigned struct_FTSENT_sz = sizeof(FTSENT);
> - unsigned struct_StringList_sz = sizeof(StringList);
> -
> - const uptr sig_ign = (uptr)SIG_IGN;
> - const uptr sig_dfl = (uptr)SIG_DFL;
> - const uptr sig_err = (uptr)SIG_ERR;
> - const uptr sa_siginfo = (uptr)SA_SIGINFO;
> -
> - 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_STAT;
> - unsigned struct_utmpx_sz = sizeof(struct utmpx);
> -
> - int map_fixed = MAP_FIXED;
> -
> - int af_inet = (int)AF_INET;
> - int af_inet6 = (int)AF_INET6;
> -
> - uptr __sanitizer_in_addr_sz(int af) {
> - if (af == AF_INET)
> - return sizeof(struct in_addr);
> - else if (af == AF_INET6)
> - return sizeof(struct in6_addr);
> - else
> - return 0;
> - }
> -
> - unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
> - int glob_nomatch = GLOB_NOMATCH;
> - int glob_altdirfunc = GLOB_ALTDIRFUNC;
> -
> - unsigned path_max = PATH_MAX;
> -
> - // ioctl arguments
> - unsigned struct_ifreq_sz = sizeof(struct ifreq);
> - unsigned struct_termios_sz = sizeof(struct termios);
> - unsigned struct_winsize_sz = sizeof(struct winsize);
> +void *__sanitizer_get_link_map_by_dlopen_handle(void *handle) {
> + void *p = nullptr;
> + return internal_dlinfo(handle, RTLD_DI_LINKMAP, &p) == 0 ? p : nullptr;
> +}
> +
> +unsigned struct_cap_rights_sz = sizeof(cap_rights_t);
> +unsigned struct_utsname_sz = sizeof(struct utsname);
> +unsigned struct_stat_sz = sizeof(struct stat);
> +unsigned struct_rusage_sz = sizeof(struct rusage);
> +unsigned struct_tm_sz = sizeof(struct tm);
> +unsigned struct_passwd_sz = sizeof(struct passwd);
> +unsigned struct_group_sz = sizeof(struct group);
> +unsigned siginfo_t_sz = sizeof(siginfo_t);
> +unsigned struct_sigaction_sz = sizeof(struct sigaction);
> +unsigned struct_stack_t_sz = sizeof(stack_t);
> +unsigned struct_itimerval_sz = sizeof(struct itimerval);
> +unsigned pthread_t_sz = sizeof(pthread_t);
> +unsigned pthread_mutex_t_sz = sizeof(pthread_mutex_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);
> +unsigned gid_t_sz = sizeof(gid_t);
> +unsigned fpos_t_sz = sizeof(fpos_t);
> +unsigned mbstate_t_sz = sizeof(mbstate_t);
> +unsigned sigset_t_sz = sizeof(sigset_t);
> +unsigned struct_timezone_sz = sizeof(struct timezone);
> +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);
> +unsigned struct_sockaddr_sz = sizeof(struct sockaddr);
> +unsigned ucontext_t_sz = sizeof(ucontext_t);
> +unsigned struct_rlimit_sz = sizeof(struct rlimit);
> +unsigned struct_timespec_sz = sizeof(struct timespec);
> +unsigned struct_utimbuf_sz = sizeof(struct utimbuf);
> +unsigned struct_itimerspec_sz = sizeof(struct itimerspec);
> +unsigned struct_timeb_sz = sizeof(struct timeb);
> +unsigned struct_msqid_ds_sz = sizeof(struct msqid_ds);
> +unsigned struct_mq_attr_sz = sizeof(struct mq_attr);
> +unsigned struct_statvfs_sz = sizeof(struct statvfs);
> +unsigned struct_shminfo_sz = sizeof(struct shminfo);
> +unsigned struct_shm_info_sz = sizeof(struct shm_info);
> +unsigned struct_regmatch_sz = sizeof(regmatch_t);
> +unsigned struct_regex_sz = sizeof(regex_t);
> +unsigned struct_fstab_sz = sizeof(struct fstab);
> +unsigned struct_FTS_sz = sizeof(FTS);
> +unsigned struct_FTSENT_sz = sizeof(FTSENT);
> +unsigned struct_StringList_sz = sizeof(StringList);
> +
> +const uptr sig_ign = (uptr)SIG_IGN;
> +const uptr sig_dfl = (uptr)SIG_DFL;
> +const uptr sig_err = (uptr)SIG_ERR;
> +const uptr sa_siginfo = (uptr)SA_SIGINFO;
> +
> +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_STAT;
> +unsigned struct_utmpx_sz = sizeof(struct utmpx);
> +
> +int map_fixed = MAP_FIXED;
> +
> +int af_inet = (int)AF_INET;
> +int af_inet6 = (int)AF_INET6;
> +
> +uptr __sanitizer_in_addr_sz(int af) {
> + if (af == AF_INET)
> + return sizeof(struct in_addr);
> + else if (af == AF_INET6)
> + return sizeof(struct in6_addr);
> + else
> + return 0;
> +}
> +
> +unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
> +int glob_nomatch = GLOB_NOMATCH;
> +int glob_altdirfunc = GLOB_ALTDIRFUNC;
> +
> +unsigned path_max = PATH_MAX;
> +
> +// ioctl arguments
> +unsigned struct_ifreq_sz = sizeof(struct ifreq);
> +unsigned struct_termios_sz = sizeof(struct termios);
> +unsigned struct_winsize_sz = sizeof(struct winsize);
> #if SOUND_VERSION >= 0x040000
> - unsigned struct_copr_buffer_sz = 0;
> - unsigned struct_copr_debug_buf_sz = 0;
> - unsigned struct_copr_msg_sz = 0;
> +unsigned struct_copr_buffer_sz = 0;
> +unsigned struct_copr_debug_buf_sz = 0;
> +unsigned struct_copr_msg_sz = 0;
> #else
> - unsigned struct_copr_buffer_sz = sizeof(struct copr_buffer);
> - unsigned struct_copr_debug_buf_sz = sizeof(struct copr_debug_buf);
> - unsigned struct_copr_msg_sz = sizeof(struct copr_msg);
> +unsigned struct_copr_buffer_sz = sizeof(struct copr_buffer);
> +unsigned struct_copr_debug_buf_sz = sizeof(struct copr_debug_buf);
> +unsigned struct_copr_msg_sz = sizeof(struct copr_msg);
> #endif
> - unsigned struct_midi_info_sz = sizeof(struct midi_info);
> - unsigned struct_mtget_sz = sizeof(struct mtget);
> - unsigned struct_mtop_sz = sizeof(struct mtop);
> - unsigned struct_sbi_instrument_sz = sizeof(struct sbi_instrument);
> - unsigned struct_seq_event_rec_sz = sizeof(struct seq_event_rec);
> - unsigned struct_synth_info_sz = sizeof(struct synth_info);
> - unsigned struct_audio_buf_info_sz = sizeof(struct audio_buf_info);
> - unsigned struct_ppp_stats_sz = sizeof(struct ppp_stats);
> - unsigned struct_sioc_sg_req_sz = sizeof(struct sioc_sg_req);
> - unsigned struct_sioc_vif_req_sz = sizeof(struct sioc_vif_req);
> - const unsigned long __sanitizer_bufsiz = BUFSIZ;
> -
> - const unsigned IOCTL_NOT_PRESENT = 0;
> -
> - unsigned IOCTL_FIOASYNC = FIOASYNC;
> - unsigned IOCTL_FIOCLEX = FIOCLEX;
> - unsigned IOCTL_FIOGETOWN = FIOGETOWN;
> - unsigned IOCTL_FIONBIO = FIONBIO;
> - unsigned IOCTL_FIONCLEX = FIONCLEX;
> - unsigned IOCTL_FIOSETOWN = FIOSETOWN;
> - unsigned IOCTL_SIOCADDMULTI = SIOCADDMULTI;
> - unsigned IOCTL_SIOCATMARK = SIOCATMARK;
> - unsigned IOCTL_SIOCDELMULTI = SIOCDELMULTI;
> - unsigned IOCTL_SIOCGIFADDR = SIOCGIFADDR;
> - unsigned IOCTL_SIOCGIFBRDADDR = SIOCGIFBRDADDR;
> - unsigned IOCTL_SIOCGIFCONF = SIOCGIFCONF;
> - unsigned IOCTL_SIOCGIFDSTADDR = SIOCGIFDSTADDR;
> - unsigned IOCTL_SIOCGIFFLAGS = SIOCGIFFLAGS;
> - unsigned IOCTL_SIOCGIFMETRIC = SIOCGIFMETRIC;
> - unsigned IOCTL_SIOCGIFMTU = SIOCGIFMTU;
> - unsigned IOCTL_SIOCGIFNETMASK = SIOCGIFNETMASK;
> - unsigned IOCTL_SIOCGPGRP = SIOCGPGRP;
> - unsigned IOCTL_SIOCSIFADDR = SIOCSIFADDR;
> - unsigned IOCTL_SIOCSIFBRDADDR = SIOCSIFBRDADDR;
> - unsigned IOCTL_SIOCSIFDSTADDR = SIOCSIFDSTADDR;
> - unsigned IOCTL_SIOCSIFFLAGS = SIOCSIFFLAGS;
> - unsigned IOCTL_SIOCSIFMETRIC = SIOCSIFMETRIC;
> - unsigned IOCTL_SIOCSIFMTU = SIOCSIFMTU;
> - unsigned IOCTL_SIOCSIFNETMASK = SIOCSIFNETMASK;
> - unsigned IOCTL_SIOCSPGRP = SIOCSPGRP;
> - unsigned IOCTL_TIOCCONS = TIOCCONS;
> - unsigned IOCTL_TIOCEXCL = TIOCEXCL;
> - unsigned IOCTL_TIOCGETD = TIOCGETD;
> - unsigned IOCTL_TIOCGPGRP = TIOCGPGRP;
> - unsigned IOCTL_TIOCGWINSZ = TIOCGWINSZ;
> - unsigned IOCTL_TIOCMBIC = TIOCMBIC;
> - unsigned IOCTL_TIOCMBIS = TIOCMBIS;
> - unsigned IOCTL_TIOCMGET = TIOCMGET;
> - unsigned IOCTL_TIOCMSET = TIOCMSET;
> - unsigned IOCTL_TIOCNOTTY = TIOCNOTTY;
> - unsigned IOCTL_TIOCNXCL = TIOCNXCL;
> - unsigned IOCTL_TIOCOUTQ = TIOCOUTQ;
> - unsigned IOCTL_TIOCPKT = TIOCPKT;
> - unsigned IOCTL_TIOCSCTTY = TIOCSCTTY;
> - unsigned IOCTL_TIOCSETD = TIOCSETD;
> - unsigned IOCTL_TIOCSPGRP = TIOCSPGRP;
> - unsigned IOCTL_TIOCSTI = TIOCSTI;
> - unsigned IOCTL_TIOCSWINSZ = TIOCSWINSZ;
> - unsigned IOCTL_SIOCGETSGCNT = SIOCGETSGCNT;
> - unsigned IOCTL_SIOCGETVIFCNT = SIOCGETVIFCNT;
> - unsigned IOCTL_MTIOCGET = MTIOCGET;
> - unsigned IOCTL_MTIOCTOP = MTIOCTOP;
> - unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE = SNDCTL_DSP_GETBLKSIZE;
> - unsigned IOCTL_SNDCTL_DSP_GETFMTS = SNDCTL_DSP_GETFMTS;
> - unsigned IOCTL_SNDCTL_DSP_NONBLOCK = SNDCTL_DSP_NONBLOCK;
> - unsigned IOCTL_SNDCTL_DSP_POST = SNDCTL_DSP_POST;
> - unsigned IOCTL_SNDCTL_DSP_RESET = SNDCTL_DSP_RESET;
> - unsigned IOCTL_SNDCTL_DSP_SETFMT = SNDCTL_DSP_SETFMT;
> - unsigned IOCTL_SNDCTL_DSP_SETFRAGMENT = SNDCTL_DSP_SETFRAGMENT;
> - unsigned IOCTL_SNDCTL_DSP_SPEED = SNDCTL_DSP_SPEED;
> - unsigned IOCTL_SNDCTL_DSP_STEREO = SNDCTL_DSP_STEREO;
> - unsigned IOCTL_SNDCTL_DSP_SUBDIVIDE = SNDCTL_DSP_SUBDIVIDE;
> - unsigned IOCTL_SNDCTL_DSP_SYNC = SNDCTL_DSP_SYNC;
> - unsigned IOCTL_SNDCTL_FM_4OP_ENABLE = SNDCTL_FM_4OP_ENABLE;
> - unsigned IOCTL_SNDCTL_FM_LOAD_INSTR = SNDCTL_FM_LOAD_INSTR;
> - unsigned IOCTL_SNDCTL_MIDI_INFO = SNDCTL_MIDI_INFO;
> - unsigned IOCTL_SNDCTL_MIDI_PRETIME = SNDCTL_MIDI_PRETIME;
> - unsigned IOCTL_SNDCTL_SEQ_CTRLRATE = SNDCTL_SEQ_CTRLRATE;
> - unsigned IOCTL_SNDCTL_SEQ_GETINCOUNT = SNDCTL_SEQ_GETINCOUNT;
> - unsigned IOCTL_SNDCTL_SEQ_GETOUTCOUNT = SNDCTL_SEQ_GETOUTCOUNT;
> - unsigned IOCTL_SNDCTL_SEQ_NRMIDIS = SNDCTL_SEQ_NRMIDIS;
> - unsigned IOCTL_SNDCTL_SEQ_NRSYNTHS = SNDCTL_SEQ_NRSYNTHS;
> - unsigned IOCTL_SNDCTL_SEQ_OUTOFBAND = SNDCTL_SEQ_OUTOFBAND;
> - unsigned IOCTL_SNDCTL_SEQ_PANIC = SNDCTL_SEQ_PANIC;
> - unsigned IOCTL_SNDCTL_SEQ_PERCMODE = SNDCTL_SEQ_PERCMODE;
> - unsigned IOCTL_SNDCTL_SEQ_RESET = SNDCTL_SEQ_RESET;
> - unsigned IOCTL_SNDCTL_SEQ_RESETSAMPLES = SNDCTL_SEQ_RESETSAMPLES;
> - unsigned IOCTL_SNDCTL_SEQ_SYNC = SNDCTL_SEQ_SYNC;
> - unsigned IOCTL_SNDCTL_SEQ_TESTMIDI = SNDCTL_SEQ_TESTMIDI;
> - unsigned IOCTL_SNDCTL_SEQ_THRESHOLD = SNDCTL_SEQ_THRESHOLD;
> - unsigned IOCTL_SNDCTL_SYNTH_INFO = SNDCTL_SYNTH_INFO;
> - unsigned IOCTL_SNDCTL_SYNTH_MEMAVL = SNDCTL_SYNTH_MEMAVL;
> - unsigned IOCTL_SNDCTL_TMR_CONTINUE = SNDCTL_TMR_CONTINUE;
> - unsigned IOCTL_SNDCTL_TMR_METRONOME = SNDCTL_TMR_METRONOME;
> - unsigned IOCTL_SNDCTL_TMR_SELECT = SNDCTL_TMR_SELECT;
> - unsigned IOCTL_SNDCTL_TMR_SOURCE = SNDCTL_TMR_SOURCE;
> - unsigned IOCTL_SNDCTL_TMR_START = SNDCTL_TMR_START;
> - unsigned IOCTL_SNDCTL_TMR_STOP = SNDCTL_TMR_STOP;
> - unsigned IOCTL_SNDCTL_TMR_TEMPO = SNDCTL_TMR_TEMPO;
> - unsigned IOCTL_SNDCTL_TMR_TIMEBASE = SNDCTL_TMR_TIMEBASE;
> - unsigned IOCTL_SOUND_MIXER_READ_ALTPCM = SOUND_MIXER_READ_ALTPCM;
> - unsigned IOCTL_SOUND_MIXER_READ_BASS = SOUND_MIXER_READ_BASS;
> - unsigned IOCTL_SOUND_MIXER_READ_CAPS = SOUND_MIXER_READ_CAPS;
> - unsigned IOCTL_SOUND_MIXER_READ_CD = SOUND_MIXER_READ_CD;
> - unsigned IOCTL_SOUND_MIXER_READ_DEVMASK = SOUND_MIXER_READ_DEVMASK;
> - unsigned IOCTL_SOUND_MIXER_READ_ENHANCE = SOUND_MIXER_READ_ENHANCE;
> - unsigned IOCTL_SOUND_MIXER_READ_IGAIN = SOUND_MIXER_READ_IGAIN;
> - unsigned IOCTL_SOUND_MIXER_READ_IMIX = SOUND_MIXER_READ_IMIX;
> - unsigned IOCTL_SOUND_MIXER_READ_LINE = SOUND_MIXER_READ_LINE;
> - unsigned IOCTL_SOUND_MIXER_READ_LINE1 = SOUND_MIXER_READ_LINE1;
> - unsigned IOCTL_SOUND_MIXER_READ_LINE2 = SOUND_MIXER_READ_LINE2;
> - unsigned IOCTL_SOUND_MIXER_READ_LINE3 = SOUND_MIXER_READ_LINE3;
> - unsigned IOCTL_SOUND_MIXER_READ_LOUD = SOUND_MIXER_READ_LOUD;
> - unsigned IOCTL_SOUND_MIXER_READ_MIC = SOUND_MIXER_READ_MIC;
> - unsigned IOCTL_SOUND_MIXER_READ_MUTE = SOUND_MIXER_READ_MUTE;
> - unsigned IOCTL_SOUND_MIXER_READ_OGAIN = SOUND_MIXER_READ_OGAIN;
> - unsigned IOCTL_SOUND_MIXER_READ_PCM = SOUND_MIXER_READ_PCM;
> - unsigned IOCTL_SOUND_MIXER_READ_RECLEV = SOUND_MIXER_READ_RECLEV;
> - unsigned IOCTL_SOUND_MIXER_READ_RECMASK = SOUND_MIXER_READ_RECMASK;
> - unsigned IOCTL_SOUND_MIXER_READ_RECSRC = SOUND_MIXER_READ_RECSRC;
> - unsigned IOCTL_SOUND_MIXER_READ_SPEAKER = SOUND_MIXER_READ_SPEAKER;
> - unsigned IOCTL_SOUND_MIXER_READ_STEREODEVS = SOUND_MIXER_READ_STEREODEVS;
> - unsigned IOCTL_SOUND_MIXER_READ_SYNTH = SOUND_MIXER_READ_SYNTH;
> - unsigned IOCTL_SOUND_MIXER_READ_TREBLE = SOUND_MIXER_READ_TREBLE;
> - unsigned IOCTL_SOUND_MIXER_READ_VOLUME = SOUND_MIXER_READ_VOLUME;
> - unsigned IOCTL_SOUND_MIXER_WRITE_ALTPCM = SOUND_MIXER_WRITE_ALTPCM;
> - unsigned IOCTL_SOUND_MIXER_WRITE_BASS = SOUND_MIXER_WRITE_BASS;
> - unsigned IOCTL_SOUND_MIXER_WRITE_CD = SOUND_MIXER_WRITE_CD;
> - unsigned IOCTL_SOUND_MIXER_WRITE_ENHANCE = SOUND_MIXER_WRITE_ENHANCE;
> - unsigned IOCTL_SOUND_MIXER_WRITE_IGAIN = SOUND_MIXER_WRITE_IGAIN;
> - unsigned IOCTL_SOUND_MIXER_WRITE_IMIX = SOUND_MIXER_WRITE_IMIX;
> - unsigned IOCTL_SOUND_MIXER_WRITE_LINE = SOUND_MIXER_WRITE_LINE;
> - unsigned IOCTL_SOUND_MIXER_WRITE_LINE1 = SOUND_MIXER_WRITE_LINE1;
> - unsigned IOCTL_SOUND_MIXER_WRITE_LINE2 = SOUND_MIXER_WRITE_LINE2;
> - unsigned IOCTL_SOUND_MIXER_WRITE_LINE3 = SOUND_MIXER_WRITE_LINE3;
> - unsigned IOCTL_SOUND_MIXER_WRITE_LOUD = SOUND_MIXER_WRITE_LOUD;
> - unsigned IOCTL_SOUND_MIXER_WRITE_MIC = SOUND_MIXER_WRITE_MIC;
> - unsigned IOCTL_SOUND_MIXER_WRITE_MUTE = SOUND_MIXER_WRITE_MUTE;
> - unsigned IOCTL_SOUND_MIXER_WRITE_OGAIN = SOUND_MIXER_WRITE_OGAIN;
> - unsigned IOCTL_SOUND_MIXER_WRITE_PCM = SOUND_MIXER_WRITE_PCM;
> - unsigned IOCTL_SOUND_MIXER_WRITE_RECLEV = SOUND_MIXER_WRITE_RECLEV;
> - unsigned IOCTL_SOUND_MIXER_WRITE_RECSRC = SOUND_MIXER_WRITE_RECSRC;
> - unsigned IOCTL_SOUND_MIXER_WRITE_SPEAKER = SOUND_MIXER_WRITE_SPEAKER;
> - unsigned IOCTL_SOUND_MIXER_WRITE_SYNTH = SOUND_MIXER_WRITE_SYNTH;
> - unsigned IOCTL_SOUND_MIXER_WRITE_TREBLE = SOUND_MIXER_WRITE_TREBLE;
> - unsigned IOCTL_SOUND_MIXER_WRITE_VOLUME = SOUND_MIXER_WRITE_VOLUME;
> - unsigned IOCTL_VT_ACTIVATE = VT_ACTIVATE;
> - unsigned IOCTL_VT_GETMODE = VT_GETMODE;
> - unsigned IOCTL_VT_OPENQRY = VT_OPENQRY;
> - unsigned IOCTL_VT_RELDISP = VT_RELDISP;
> - unsigned IOCTL_VT_SETMODE = VT_SETMODE;
> - unsigned IOCTL_VT_WAITACTIVE = VT_WAITACTIVE;
> - unsigned IOCTL_GIO_SCRNMAP = GIO_SCRNMAP;
> - unsigned IOCTL_KDDISABIO = KDDISABIO;
> - unsigned IOCTL_KDENABIO = KDENABIO;
> - unsigned IOCTL_KDGETLED = KDGETLED;
> - unsigned IOCTL_KDGETMODE = KDGETMODE;
> - unsigned IOCTL_KDGKBMODE = KDGKBMODE;
> - unsigned IOCTL_KDGKBTYPE = KDGKBTYPE;
> - unsigned IOCTL_KDMKTONE = KDMKTONE;
> - unsigned IOCTL_KDSETLED = KDSETLED;
> - unsigned IOCTL_KDSETMODE = KDSETMODE;
> - unsigned IOCTL_KDSKBMODE = KDSKBMODE;
> - unsigned IOCTL_KIOCSOUND = KIOCSOUND;
> - unsigned IOCTL_PIO_SCRNMAP = PIO_SCRNMAP;
> - unsigned IOCTL_SNDCTL_DSP_GETISPACE = SNDCTL_DSP_GETISPACE;
> -
> - const int si_SEGV_MAPERR = SEGV_MAPERR;
> - const int si_SEGV_ACCERR = SEGV_ACCERR;
> - const int unvis_valid = UNVIS_VALID;
> - const int unvis_validpush = UNVIS_VALIDPUSH;
> -} // namespace __sanitizer
> +unsigned struct_midi_info_sz = sizeof(struct midi_info);
> +unsigned struct_mtget_sz = sizeof(struct mtget);
> +unsigned struct_mtop_sz = sizeof(struct mtop);
> +unsigned struct_sbi_instrument_sz = sizeof(struct sbi_instrument);
> +unsigned struct_seq_event_rec_sz = sizeof(struct seq_event_rec);
> +unsigned struct_synth_info_sz = sizeof(struct synth_info);
> +unsigned struct_audio_buf_info_sz = sizeof(struct audio_buf_info);
> +unsigned struct_ppp_stats_sz = sizeof(struct ppp_stats);
> +unsigned struct_sioc_sg_req_sz = sizeof(struct sioc_sg_req);
> +unsigned struct_sioc_vif_req_sz = sizeof(struct sioc_vif_req);
> +const unsigned long __sanitizer_bufsiz = BUFSIZ;
> +
> +const unsigned IOCTL_NOT_PRESENT = 0;
> +
> +unsigned IOCTL_FIOASYNC = FIOASYNC;
> +unsigned IOCTL_FIOCLEX = FIOCLEX;
> +unsigned IOCTL_FIOGETOWN = FIOGETOWN;
> +unsigned IOCTL_FIONBIO = FIONBIO;
> +unsigned IOCTL_FIONCLEX = FIONCLEX;
> +unsigned IOCTL_FIOSETOWN = FIOSETOWN;
> +unsigned IOCTL_SIOCADDMULTI = SIOCADDMULTI;
> +unsigned IOCTL_SIOCATMARK = SIOCATMARK;
> +unsigned IOCTL_SIOCDELMULTI = SIOCDELMULTI;
> +unsigned IOCTL_SIOCGIFADDR = SIOCGIFADDR;
> +unsigned IOCTL_SIOCGIFBRDADDR = SIOCGIFBRDADDR;
> +unsigned IOCTL_SIOCGIFCONF = SIOCGIFCONF;
> +unsigned IOCTL_SIOCGIFDSTADDR = SIOCGIFDSTADDR;
> +unsigned IOCTL_SIOCGIFFLAGS = SIOCGIFFLAGS;
> +unsigned IOCTL_SIOCGIFMETRIC = SIOCGIFMETRIC;
> +unsigned IOCTL_SIOCGIFMTU = SIOCGIFMTU;
> +unsigned IOCTL_SIOCGIFNETMASK = SIOCGIFNETMASK;
> +unsigned IOCTL_SIOCGPGRP = SIOCGPGRP;
> +unsigned IOCTL_SIOCSIFADDR = SIOCSIFADDR;
> +unsigned IOCTL_SIOCSIFBRDADDR = SIOCSIFBRDADDR;
> +unsigned IOCTL_SIOCSIFDSTADDR = SIOCSIFDSTADDR;
> +unsigned IOCTL_SIOCSIFFLAGS = SIOCSIFFLAGS;
> +unsigned IOCTL_SIOCSIFMETRIC = SIOCSIFMETRIC;
> +unsigned IOCTL_SIOCSIFMTU = SIOCSIFMTU;
> +unsigned IOCTL_SIOCSIFNETMASK = SIOCSIFNETMASK;
> +unsigned IOCTL_SIOCSPGRP = SIOCSPGRP;
> +unsigned IOCTL_TIOCCONS = TIOCCONS;
> +unsigned IOCTL_TIOCEXCL = TIOCEXCL;
> +unsigned IOCTL_TIOCGETD = TIOCGETD;
> +unsigned IOCTL_TIOCGPGRP = TIOCGPGRP;
> +unsigned IOCTL_TIOCGWINSZ = TIOCGWINSZ;
> +unsigned IOCTL_TIOCMBIC = TIOCMBIC;
> +unsigned IOCTL_TIOCMBIS = TIOCMBIS;
> +unsigned IOCTL_TIOCMGET = TIOCMGET;
> +unsigned IOCTL_TIOCMSET = TIOCMSET;
> +unsigned IOCTL_TIOCNOTTY = TIOCNOTTY;
> +unsigned IOCTL_TIOCNXCL = TIOCNXCL;
> +unsigned IOCTL_TIOCOUTQ = TIOCOUTQ;
> +unsigned IOCTL_TIOCPKT = TIOCPKT;
> +unsigned IOCTL_TIOCSCTTY = TIOCSCTTY;
> +unsigned IOCTL_TIOCSETD = TIOCSETD;
> +unsigned IOCTL_TIOCSPGRP = TIOCSPGRP;
> +unsigned IOCTL_TIOCSTI = TIOCSTI;
> +unsigned IOCTL_TIOCSWINSZ = TIOCSWINSZ;
> +unsigned IOCTL_SIOCGETSGCNT = SIOCGETSGCNT;
> +unsigned IOCTL_SIOCGETVIFCNT = SIOCGETVIFCNT;
> +unsigned IOCTL_MTIOCGET = MTIOCGET;
> +unsigned IOCTL_MTIOCTOP = MTIOCTOP;
> +unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE = SNDCTL_DSP_GETBLKSIZE;
> +unsigned IOCTL_SNDCTL_DSP_GETFMTS = SNDCTL_DSP_GETFMTS;
> +unsigned IOCTL_SNDCTL_DSP_NONBLOCK = SNDCTL_DSP_NONBLOCK;
> +unsigned IOCTL_SNDCTL_DSP_POST = SNDCTL_DSP_POST;
> +unsigned IOCTL_SNDCTL_DSP_RESET = SNDCTL_DSP_RESET;
> +unsigned IOCTL_SNDCTL_DSP_SETFMT = SNDCTL_DSP_SETFMT;
> +unsigned IOCTL_SNDCTL_DSP_SETFRAGMENT = SNDCTL_DSP_SETFRAGMENT;
> +unsigned IOCTL_SNDCTL_DSP_SPEED = SNDCTL_DSP_SPEED;
> +unsigned IOCTL_SNDCTL_DSP_STEREO = SNDCTL_DSP_STEREO;
> +unsigned IOCTL_SNDCTL_DSP_SUBDIVIDE = SNDCTL_DSP_SUBDIVIDE;
> +unsigned IOCTL_SNDCTL_DSP_SYNC = SNDCTL_DSP_SYNC;
> +unsigned IOCTL_SNDCTL_FM_4OP_ENABLE = SNDCTL_FM_4OP_ENABLE;
> +unsigned IOCTL_SNDCTL_FM_LOAD_INSTR = SNDCTL_FM_LOAD_INSTR;
> +unsigned IOCTL_SNDCTL_MIDI_INFO = SNDCTL_MIDI_INFO;
> +unsigned IOCTL_SNDCTL_MIDI_PRETIME = SNDCTL_MIDI_PRETIME;
> +unsigned IOCTL_SNDCTL_SEQ_CTRLRATE = SNDCTL_SEQ_CTRLRATE;
> +unsigned IOCTL_SNDCTL_SEQ_GETINCOUNT = SNDCTL_SEQ_GETINCOUNT;
> +unsigned IOCTL_SNDCTL_SEQ_GETOUTCOUNT = SNDCTL_SEQ_GETOUTCOUNT;
> +unsigned IOCTL_SNDCTL_SEQ_NRMIDIS = SNDCTL_SEQ_NRMIDIS;
> +unsigned IOCTL_SNDCTL_SEQ_NRSYNTHS = SNDCTL_SEQ_NRSYNTHS;
> +unsigned IOCTL_SNDCTL_SEQ_OUTOFBAND = SNDCTL_SEQ_OUTOFBAND;
> +unsigned IOCTL_SNDCTL_SEQ_PANIC = SNDCTL_SEQ_PANIC;
> +unsigned IOCTL_SNDCTL_SEQ_PERCMODE = SNDCTL_SEQ_PERCMODE;
> +unsigned IOCTL_SNDCTL_SEQ_RESET = SNDCTL_SEQ_RESET;
> +unsigned IOCTL_SNDCTL_SEQ_RESETSAMPLES = SNDCTL_SEQ_RESETSAMPLES;
> +unsigned IOCTL_SNDCTL_SEQ_SYNC = SNDCTL_SEQ_SYNC;
> +unsigned IOCTL_SNDCTL_SEQ_TESTMIDI = SNDCTL_SEQ_TESTMIDI;
> +unsigned IOCTL_SNDCTL_SEQ_THRESHOLD = SNDCTL_SEQ_THRESHOLD;
> +unsigned IOCTL_SNDCTL_SYNTH_INFO = SNDCTL_SYNTH_INFO;
> +unsigned IOCTL_SNDCTL_SYNTH_MEMAVL = SNDCTL_SYNTH_MEMAVL;
> +unsigned IOCTL_SNDCTL_TMR_CONTINUE = SNDCTL_TMR_CONTINUE;
> +unsigned IOCTL_SNDCTL_TMR_METRONOME = SNDCTL_TMR_METRONOME;
> +unsigned IOCTL_SNDCTL_TMR_SELECT = SNDCTL_TMR_SELECT;
> +unsigned IOCTL_SNDCTL_TMR_SOURCE = SNDCTL_TMR_SOURCE;
> +unsigned IOCTL_SNDCTL_TMR_START = SNDCTL_TMR_START;
> +unsigned IOCTL_SNDCTL_TMR_STOP = SNDCTL_TMR_STOP;
> +unsigned IOCTL_SNDCTL_TMR_TEMPO = SNDCTL_TMR_TEMPO;
> +unsigned IOCTL_SNDCTL_TMR_TIMEBASE = SNDCTL_TMR_TIMEBASE;
> +unsigned IOCTL_SOUND_MIXER_READ_ALTPCM = SOUND_MIXER_READ_ALTPCM;
> +unsigned IOCTL_SOUND_MIXER_READ_BASS = SOUND_MIXER_READ_BASS;
> +unsigned IOCTL_SOUND_MIXER_READ_CAPS = SOUND_MIXER_READ_CAPS;
> +unsigned IOCTL_SOUND_MIXER_READ_CD = SOUND_MIXER_READ_CD;
> +unsigned IOCTL_SOUND_MIXER_READ_DEVMASK = SOUND_MIXER_READ_DEVMASK;
> +unsigned IOCTL_SOUND_MIXER_READ_ENHANCE = SOUND_MIXER_READ_ENHANCE;
> +unsigned IOCTL_SOUND_MIXER_READ_IGAIN = SOUND_MIXER_READ_IGAIN;
> +unsigned IOCTL_SOUND_MIXER_READ_IMIX = SOUND_MIXER_READ_IMIX;
> +unsigned IOCTL_SOUND_MIXER_READ_LINE = SOUND_MIXER_READ_LINE;
> +unsigned IOCTL_SOUND_MIXER_READ_LINE1 = SOUND_MIXER_READ_LINE1;
> +unsigned IOCTL_SOUND_MIXER_READ_LINE2 = SOUND_MIXER_READ_LINE2;
> +unsigned IOCTL_SOUND_MIXER_READ_LINE3 = SOUND_MIXER_READ_LINE3;
> +unsigned IOCTL_SOUND_MIXER_READ_LOUD = SOUND_MIXER_READ_LOUD;
> +unsigned IOCTL_SOUND_MIXER_READ_MIC = SOUND_MIXER_READ_MIC;
> +unsigned IOCTL_SOUND_MIXER_READ_MUTE = SOUND_MIXER_READ_MUTE;
> +unsigned IOCTL_SOUND_MIXER_READ_OGAIN = SOUND_MIXER_READ_OGAIN;
> +unsigned IOCTL_SOUND_MIXER_READ_PCM = SOUND_MIXER_READ_PCM;
> +unsigned IOCTL_SOUND_MIXER_READ_RECLEV = SOUND_MIXER_READ_RECLEV;
> +unsigned IOCTL_SOUND_MIXER_READ_RECMASK = SOUND_MIXER_READ_RECMASK;
> +unsigned IOCTL_SOUND_MIXER_READ_RECSRC = SOUND_MIXER_READ_RECSRC;
> +unsigned IOCTL_SOUND_MIXER_READ_SPEAKER = SOUND_MIXER_READ_SPEAKER;
> +unsigned IOCTL_SOUND_MIXER_READ_STEREODEVS = SOUND_MIXER_READ_STEREODEVS;
> +unsigned IOCTL_SOUND_MIXER_READ_SYNTH = SOUND_MIXER_READ_SYNTH;
> +unsigned IOCTL_SOUND_MIXER_READ_TREBLE = SOUND_MIXER_READ_TREBLE;
> +unsigned IOCTL_SOUND_MIXER_READ_VOLUME = SOUND_MIXER_READ_VOLUME;
> +unsigned IOCTL_SOUND_MIXER_WRITE_ALTPCM = SOUND_MIXER_WRITE_ALTPCM;
> +unsigned IOCTL_SOUND_MIXER_WRITE_BASS = SOUND_MIXER_WRITE_BASS;
> +unsigned IOCTL_SOUND_MIXER_WRITE_CD = SOUND_MIXER_WRITE_CD;
> +unsigned IOCTL_SOUND_MIXER_WRITE_ENHANCE = SOUND_MIXER_WRITE_ENHANCE;
> +unsigned IOCTL_SOUND_MIXER_WRITE_IGAIN = SOUND_MIXER_WRITE_IGAIN;
> +unsigned IOCTL_SOUND_MIXER_WRITE_IMIX = SOUND_MIXER_WRITE_IMIX;
> +unsigned IOCTL_SOUND_MIXER_WRITE_LINE = SOUND_MIXER_WRITE_LINE;
> +unsigned IOCTL_SOUND_MIXER_WRITE_LINE1 = SOUND_MIXER_WRITE_LINE1;
> +unsigned IOCTL_SOUND_MIXER_WRITE_LINE2 = SOUND_MIXER_WRITE_LINE2;
> +unsigned IOCTL_SOUND_MIXER_WRITE_LINE3 = SOUND_MIXER_WRITE_LINE3;
> +unsigned IOCTL_SOUND_MIXER_WRITE_LOUD = SOUND_MIXER_WRITE_LOUD;
> +unsigned IOCTL_SOUND_MIXER_WRITE_MIC = SOUND_MIXER_WRITE_MIC;
> +unsigned IOCTL_SOUND_MIXER_WRITE_MUTE = SOUND_MIXER_WRITE_MUTE;
> +unsigned IOCTL_SOUND_MIXER_WRITE_OGAIN = SOUND_MIXER_WRITE_OGAIN;
> +unsigned IOCTL_SOUND_MIXER_WRITE_PCM = SOUND_MIXER_WRITE_PCM;
> +unsigned IOCTL_SOUND_MIXER_WRITE_RECLEV = SOUND_MIXER_WRITE_RECLEV;
> +unsigned IOCTL_SOUND_MIXER_WRITE_RECSRC = SOUND_MIXER_WRITE_RECSRC;
> +unsigned IOCTL_SOUND_MIXER_WRITE_SPEAKER = SOUND_MIXER_WRITE_SPEAKER;
> +unsigned IOCTL_SOUND_MIXER_WRITE_SYNTH = SOUND_MIXER_WRITE_SYNTH;
> +unsigned IOCTL_SOUND_MIXER_WRITE_TREBLE = SOUND_MIXER_WRITE_TREBLE;
> +unsigned IOCTL_SOUND_MIXER_WRITE_VOLUME = SOUND_MIXER_WRITE_VOLUME;
> +unsigned IOCTL_VT_ACTIVATE = VT_ACTIVATE;
> +unsigned IOCTL_VT_GETMODE = VT_GETMODE;
> +unsigned IOCTL_VT_OPENQRY = VT_OPENQRY;
> +unsigned IOCTL_VT_RELDISP = VT_RELDISP;
> +unsigned IOCTL_VT_SETMODE = VT_SETMODE;
> +unsigned IOCTL_VT_WAITACTIVE = VT_WAITACTIVE;
> +unsigned IOCTL_GIO_SCRNMAP = GIO_SCRNMAP;
> +unsigned IOCTL_KDDISABIO = KDDISABIO;
> +unsigned IOCTL_KDENABIO = KDENABIO;
> +unsigned IOCTL_KDGETLED = KDGETLED;
> +unsigned IOCTL_KDGETMODE = KDGETMODE;
> +unsigned IOCTL_KDGKBMODE = KDGKBMODE;
> +unsigned IOCTL_KDGKBTYPE = KDGKBTYPE;
> +unsigned IOCTL_KDMKTONE = KDMKTONE;
> +unsigned IOCTL_KDSETLED = KDSETLED;
> +unsigned IOCTL_KDSETMODE = KDSETMODE;
> +unsigned IOCTL_KDSKBMODE = KDSKBMODE;
> +unsigned IOCTL_KIOCSOUND = KIOCSOUND;
> +unsigned IOCTL_PIO_SCRNMAP = PIO_SCRNMAP;
> +unsigned IOCTL_SNDCTL_DSP_GETISPACE = SNDCTL_DSP_GETISPACE;
> +
> +const int si_SEGV_MAPERR = SEGV_MAPERR;
> +const int si_SEGV_ACCERR = SEGV_ACCERR;
> +const int unvis_valid = UNVIS_VALID;
> +const int unvis_validpush = UNVIS_VALIDPUSH;
> +} // namespace __sanitizer
>
> using namespace __sanitizer;
>
> diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.h b/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.h
> index 71cf5b9c357..5e0ca9c7d78 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.h
> +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.h
> @@ -18,18 +18,17 @@
>
> #include "sanitizer_internal_defs.h"
> #include "sanitizer_platform.h"
> -
> #include "sanitizer_platform_limits_posix.h"
>
> -// FreeBSD's dlopen() returns a pointer to an Obj_Entry structure that
> -// incorporates the map structure.
> -# define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \
> - ((link_map*)((handle) == nullptr ? nullptr : ((char*)(handle) + 560)))
> // Get sys/_types.h, because that tells us whether 64-bit inodes are
> // used in struct dirent below.
> #include <sys/_types.h>
>
> namespace __sanitizer {
> +void *__sanitizer_get_link_map_by_dlopen_handle(void *handle);
> +#define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \
> + (link_map *)__sanitizer_get_link_map_by_dlopen_handle(handle)
> +
> extern unsigned struct_utsname_sz;
> extern unsigned struct_stat_sz;
> #if defined(__powerpc64__)
> @@ -53,6 +52,7 @@ extern unsigned struct_timezone_sz;
> extern unsigned struct_tms_sz;
> extern unsigned struct_itimerspec_sz;
> extern unsigned struct_sigevent_sz;
> +extern unsigned struct_stack_t_sz;
> extern unsigned struct_sched_param_sz;
> extern unsigned struct_statfs64_sz;
> extern unsigned struct_statfs_sz;
> @@ -147,7 +147,7 @@ struct __sanitizer_ifaddrs {
> unsigned int ifa_flags;
> void *ifa_addr; // (struct sockaddr *)
> void *ifa_netmask; // (struct sockaddr *)
> -# undef ifa_dstaddr
> +#undef ifa_dstaddr
> void *ifa_dstaddr; // (struct sockaddr *)
> void *ifa_data;
> };
> @@ -630,27 +630,27 @@ extern unsigned struct_cap_rights_sz;
>
> extern unsigned struct_fstab_sz;
> extern unsigned struct_StringList_sz;
> -} // namespace __sanitizer
> +} // 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) == \
> +#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) == \
> +#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))
>
> #define SIGACTION_SYMNAME sigaction
>
> #endif
>
> -#endif // SANITIZER_FREEBSD
> +#endif // SANITIZER_FREEBSD
> diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cpp b/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cpp
> index f22f5039128..c51327e1269 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cpp
> @@ -26,12 +26,9 @@
>
> // 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. Beware that with <sys/stat.h>, struct stat
> -// takes the form of struct stat64 on 32-bit platforms if _FILE_OFFSET_BITS=64.
> -// Also, for some platforms (e.g. mips) there are additional members in the
> -// <sys/stat.h> struct stat:s.
> +// fine with newer headers, too.
> #include <linux/posix_types.h>
> -#if defined(__x86_64__)
> +#if defined(__x86_64__) || defined(__mips__)
> #include <sys/stat.h>
> #else
> #define ino_t __kernel_ino_t
> diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_netbsd.cpp b/libsanitizer/sanitizer_common/sanitizer_platform_limits_netbsd.cpp
> index f01de6c995e..25da334b63f 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_netbsd.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_netbsd.cpp
> @@ -17,6 +17,7 @@
>
> #define _KMEMUSER
> #define RAY_DO_SIGLEV
> +#define __LEGACY_PT_LWPINFO
>
> // clang-format off
> #include <sys/param.h>
> @@ -71,6 +72,15 @@
> #include <sys/msg.h>
> #include <sys/mtio.h>
> #include <sys/ptrace.h>
> +
> +// Compat for NetBSD < 9.99.30.
> +#ifndef PT_LWPSTATUS
> +#define PT_LWPSTATUS 24
> +#endif
> +#ifndef PT_LWPNEXT
> +#define PT_LWPNEXT 25
> +#endif
> +
> #include <sys/resource.h>
> #include <sys/sem.h>
> #include <sys/sha1.h>
> @@ -109,7 +119,12 @@
> #include <dev/dmover/dmover_io.h>
> #include <dev/dtv/dtvio_demux.h>
> #include <dev/dtv/dtvio_frontend.h>
> +#if !__NetBSD_Prereq__(9, 99, 26)
> #include <dev/filemon/filemon.h>
> +#else
> +#define FILEMON_SET_FD _IOWR('S', 1, int)
> +#define FILEMON_SET_PID _IOWR('S', 2, pid_t)
> +#endif
> #include <dev/hdaudio/hdaudioio.h>
> #include <dev/hdmicec/hdmicecio.h>
> #include <dev/hpc/hpcfbio.h>
> @@ -146,12 +161,121 @@
> #include <net/slip.h>
> #include <netbt/hci.h>
> #include <netinet/ip_compat.h>
> +#if __has_include(<netinet/ip_fil.h>)
> #include <netinet/ip_fil.h>
> #include <netinet/ip_nat.h>
> #include <netinet/ip_proxy.h>
> +#else
> +/* Fallback for MKIPFILTER=no */
> +
> +typedef struct ap_control {
> + char apc_label[16];
> + char apc_config[16];
> + unsigned char apc_p;
> + unsigned long apc_cmd;
> + unsigned long apc_arg;
> + void *apc_data;
> + size_t apc_dsize;
> +} ap_ctl_t;
> +
> +typedef struct ipftq {
> + ipfmutex_t ifq_lock;
> + unsigned int ifq_ttl;
> + void *ifq_head;
> + void **ifq_tail;
> + void *ifq_next;
> + void **ifq_pnext;
> + int ifq_ref;
> + unsigned int ifq_flags;
> +} ipftq_t;
> +
> +typedef struct ipfobj {
> + uint32_t ipfo_rev;
> + uint32_t ipfo_size;
> + void *ipfo_ptr;
> + int ipfo_type;
> + int ipfo_offset;
> + int ipfo_retval;
> + unsigned char ipfo_xxxpad[28];
> +} ipfobj_t;
> +
> +#define SIOCADNAT _IOW('r', 60, struct ipfobj)
> +#define SIOCRMNAT _IOW('r', 61, struct ipfobj)
> +#define SIOCGNATS _IOWR('r', 62, struct ipfobj)
> +#define SIOCGNATL _IOWR('r', 63, struct ipfobj)
> +#define SIOCPURGENAT _IOWR('r', 100, struct ipfobj)
> +#endif
> #include <netinet6/in6_var.h>
> #include <netinet6/nd6.h>
> +#if !__NetBSD_Prereq__(9, 99, 51)
> #include <netsmb/smb_dev.h>
> +#else
> +struct smbioc_flags {
> + int ioc_level;
> + int ioc_mask;
> + int ioc_flags;
> +};
> +struct smbioc_oshare {
> + int ioc_opt;
> + int ioc_stype;
> + char ioc_share[129];
> + char ioc_password[129];
> + uid_t ioc_owner;
> + gid_t ioc_group;
> + mode_t ioc_mode;
> + mode_t ioc_rights;
> +};
> +struct smbioc_ossn {
> + int ioc_opt;
> + uint32_t ioc_svlen;
> + struct sockaddr *ioc_server;
> + uint32_t ioc_lolen;
> + struct sockaddr *ioc_local;
> + char ioc_srvname[16];
> + int ioc_timeout;
> + int ioc_retrycount;
> + char ioc_localcs[16];
> + char ioc_servercs[16];
> + char ioc_user[129];
> + char ioc_workgroup[129];
> + char ioc_password[129];
> + uid_t ioc_owner;
> + gid_t ioc_group;
> + mode_t ioc_mode;
> + mode_t ioc_rights;
> +};
> +struct smbioc_lookup {
> + int ioc_level;
> + int ioc_flags;
> + struct smbioc_ossn ioc_ssn;
> + struct smbioc_oshare ioc_sh;
> +};
> +struct smbioc_rq {
> + u_char ioc_cmd;
> + u_char ioc_twc;
> + void *ioc_twords;
> + u_short ioc_tbc;
> + void *ioc_tbytes;
> + int ioc_rpbufsz;
> + char *ioc_rpbuf;
> + u_char ioc_rwc;
> + u_short ioc_rbc;
> +};
> +struct smbioc_rw {
> + u_int16_t ioc_fh;
> + char *ioc_base;
> + off_t ioc_offset;
> + int ioc_cnt;
> +};
> +#define SMBIOC_OPENSESSION _IOW('n', 100, struct smbioc_ossn)
> +#define SMBIOC_OPENSHARE _IOW('n', 101, struct smbioc_oshare)
> +#define SMBIOC_REQUEST _IOWR('n', 102, struct smbioc_rq)
> +#define SMBIOC_T2RQ _IOWR('n', 103, struct smbioc_t2rq)
> +#define SMBIOC_SETFLAGS _IOW('n', 104, struct smbioc_flags)
> +#define SMBIOC_LOOKUP _IOW('n', 106, struct smbioc_lookup)
> +#define SMBIOC_READ _IOWR('n', 107, struct smbioc_rw)
> +#define SMBIOC_WRITE _IOWR('n', 108, struct smbioc_rw)
> +#endif
> #include <dev/biovar.h>
> #include <dev/bluetooth/btdev.h>
> #include <dev/bluetooth/btsco.h>
> @@ -175,7 +299,21 @@
> #include <dev/sun/vuid_event.h>
> #include <dev/tc/sticio.h>
> #include <dev/usb/ukyopon.h>
> +#if !__NetBSD_Prereq__(9, 99, 44)
> #include <dev/usb/urio.h>
> +#else
> +struct urio_command {
> + unsigned short length;
> + int request;
> + int requesttype;
> + int value;
> + int index;
> + void *buffer;
> + int timeout;
> +};
> +#define URIO_SEND_COMMAND _IOWR('U', 200, struct urio_command)
> +#define URIO_RECV_COMMAND _IOWR('U', 201, struct urio_command)
> +#endif
> #include <dev/usb/usb.h>
> #include <dev/usb/utoppy.h>
> #include <dev/vme/xio.h>
> @@ -184,6 +322,7 @@
> #include <dev/wscons/wsdisplay_usl_io.h>
> #include <fs/autofs/autofs_ioctl.h>
> #include <dirent.h>
> +#include <dlfcn.h>
> #include <glob.h>
> #include <grp.h>
> #include <ifaddrs.h>
> @@ -229,9 +368,15 @@
>
> // Include these after system headers to avoid name clashes and ambiguities.
> #include "sanitizer_internal_defs.h"
> +#include "sanitizer_libc.h"
> #include "sanitizer_platform_limits_netbsd.h"
>
> namespace __sanitizer {
> +void *__sanitizer_get_link_map_by_dlopen_handle(void* handle) {
> + void *p = nullptr;
> + return internal_dlinfo(handle, RTLD_DI_LINKMAP, &p) == 0 ? p : nullptr;
> +}
> +
> unsigned struct_utsname_sz = sizeof(struct utsname);
> unsigned struct_stat_sz = sizeof(struct stat);
> unsigned struct_rusage_sz = sizeof(struct rusage);
> @@ -240,6 +385,7 @@ unsigned struct_passwd_sz = sizeof(struct passwd);
> unsigned struct_group_sz = sizeof(struct group);
> unsigned siginfo_t_sz = sizeof(siginfo_t);
> unsigned struct_sigaction_sz = sizeof(struct sigaction);
> +unsigned struct_stack_t_sz = sizeof(stack_t);
> unsigned struct_itimerval_sz = sizeof(struct itimerval);
> unsigned pthread_t_sz = sizeof(pthread_t);
> unsigned pthread_mutex_t_sz = sizeof(pthread_mutex_t);
> @@ -287,6 +433,8 @@ int ptrace_pt_get_event_mask = PT_GET_EVENT_MASK;
> int ptrace_pt_get_process_state = PT_GET_PROCESS_STATE;
> int ptrace_pt_set_siginfo = PT_SET_SIGINFO;
> int ptrace_pt_get_siginfo = PT_GET_SIGINFO;
> +int ptrace_pt_lwpstatus = PT_LWPSTATUS;
> +int ptrace_pt_lwpnext = PT_LWPNEXT;
> int ptrace_piod_read_d = PIOD_READ_D;
> int ptrace_piod_write_d = PIOD_WRITE_D;
> int ptrace_piod_read_i = PIOD_READ_I;
> @@ -319,6 +467,8 @@ int ptrace_pt_getdbregs = -1;
>
> unsigned struct_ptrace_ptrace_io_desc_struct_sz = sizeof(struct ptrace_io_desc);
> unsigned struct_ptrace_ptrace_lwpinfo_struct_sz = sizeof(struct ptrace_lwpinfo);
> +unsigned struct_ptrace_ptrace_lwpstatus_struct_sz =
> + sizeof(struct __sanitizer_ptrace_lwpstatus);
> unsigned struct_ptrace_ptrace_event_struct_sz = sizeof(ptrace_event_t);
> unsigned struct_ptrace_ptrace_siginfo_struct_sz = sizeof(ptrace_siginfo_t);
>
> @@ -698,6 +848,7 @@ unsigned struct_nvmm_ioc_machine_configure_sz =
> sizeof(nvmm_ioc_machine_configure);
> unsigned struct_nvmm_ioc_vcpu_create_sz = sizeof(nvmm_ioc_vcpu_create);
> unsigned struct_nvmm_ioc_vcpu_destroy_sz = sizeof(nvmm_ioc_vcpu_destroy);
> +unsigned struct_nvmm_ioc_vcpu_configure_sz = sizeof(nvmm_ioc_vcpu_configure);
> unsigned struct_nvmm_ioc_vcpu_setstate_sz = sizeof(nvmm_ioc_vcpu_destroy);
> unsigned struct_nvmm_ioc_vcpu_getstate_sz = sizeof(nvmm_ioc_vcpu_getstate);
> unsigned struct_nvmm_ioc_vcpu_inject_sz = sizeof(nvmm_ioc_vcpu_inject);
> @@ -1458,6 +1609,7 @@ unsigned IOCTL_NVMM_IOC_MACHINE_DESTROY = NVMM_IOC_MACHINE_DESTROY;
> unsigned IOCTL_NVMM_IOC_MACHINE_CONFIGURE = NVMM_IOC_MACHINE_CONFIGURE;
> unsigned IOCTL_NVMM_IOC_VCPU_CREATE = NVMM_IOC_VCPU_CREATE;
> unsigned IOCTL_NVMM_IOC_VCPU_DESTROY = NVMM_IOC_VCPU_DESTROY;
> +unsigned IOCTL_NVMM_IOC_VCPU_CONFIGURE = NVMM_IOC_VCPU_CONFIGURE;
> unsigned IOCTL_NVMM_IOC_VCPU_SETSTATE = NVMM_IOC_VCPU_SETSTATE;
> unsigned IOCTL_NVMM_IOC_VCPU_GETSTATE = NVMM_IOC_VCPU_GETSTATE;
> unsigned IOCTL_NVMM_IOC_VCPU_INJECT = NVMM_IOC_VCPU_INJECT;
> @@ -1534,6 +1686,7 @@ unsigned IOCTL_IOC_NPF_STATS = IOC_NPF_STATS;
> unsigned IOCTL_IOC_NPF_SAVE = IOC_NPF_SAVE;
> unsigned IOCTL_IOC_NPF_RULE = IOC_NPF_RULE;
> unsigned IOCTL_IOC_NPF_CONN_LOOKUP = IOC_NPF_CONN_LOOKUP;
> +unsigned IOCTL_IOC_NPF_TABLE_REPLACE = IOC_NPF_TABLE_REPLACE;
> unsigned IOCTL_PPPOESETPARMS = PPPOESETPARMS;
> unsigned IOCTL_PPPOEGETPARMS = PPPOEGETPARMS;
> unsigned IOCTL_PPPOEGETSESSION = PPPOEGETSESSION;
> @@ -2392,4 +2545,42 @@ CHECK_SIZE_AND_OFFSET(modctl_load_t, ml_flags);
> CHECK_SIZE_AND_OFFSET(modctl_load_t, ml_props);
> CHECK_SIZE_AND_OFFSET(modctl_load_t, ml_propslen);
>
> +// Compat with 9.0
> +struct statvfs90 {
> + unsigned long f_flag;
> + unsigned long f_bsize;
> + unsigned long f_frsize;
> + unsigned long f_iosize;
> +
> + u64 f_blocks;
> + u64 f_bfree;
> + u64 f_bavail;
> + u64 f_bresvd;
> +
> + u64 f_files;
> + u64 f_ffree;
> + u64 f_favail;
> + u64 f_fresvd;
> +
> + u64 f_syncreads;
> + u64 f_syncwrites;
> +
> + u64 f_asyncreads;
> + u64 f_asyncwrites;
> +
> + struct {
> + s32 __fsid_val[2];
> + } f_fsidx;
> + unsigned long f_fsid;
> + unsigned long f_namemax;
> + u32 f_owner;
> +
> + u32 f_spare[4];
> +
> + char f_fstypename[32];
> + char f_mntonname[32];
> + char f_mntfromname[32];
> +};
> +unsigned struct_statvfs90_sz = sizeof(struct statvfs90);
> +
> #endif // SANITIZER_NETBSD
> diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_netbsd.h b/libsanitizer/sanitizer_common/sanitizer_platform_limits_netbsd.h
> index 419d830c69e..d80280d9bf8 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_netbsd.h
> +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_netbsd.h
> @@ -19,18 +19,11 @@
> #include "sanitizer_internal_defs.h"
> #include "sanitizer_platform.h"
>
> -#define _GET_LINK_MAP_BY_DLOPEN_HANDLE(handle, shift) \
> - ((link_map *)((handle) == nullptr ? nullptr : ((char *)(handle) + (shift))))
> -
> -#if defined(__x86_64__)
> -#define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \
> - _GET_LINK_MAP_BY_DLOPEN_HANDLE(handle, 264)
> -#elif defined(__i386__)
> -#define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \
> - _GET_LINK_MAP_BY_DLOPEN_HANDLE(handle, 136)
> -#endif
> -
> namespace __sanitizer {
> +void *__sanitizer_get_link_map_by_dlopen_handle(void *handle);
> +# define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \
> + (link_map *)__sanitizer_get_link_map_by_dlopen_handle(handle)
> +
> extern unsigned struct_utsname_sz;
> extern unsigned struct_stat_sz;
> extern unsigned struct_rusage_sz;
> @@ -48,6 +41,7 @@ extern unsigned struct_timezone_sz;
> extern unsigned struct_tms_sz;
> extern unsigned struct_itimerspec_sz;
> extern unsigned struct_sigevent_sz;
> +extern unsigned struct_stack_t_sz;
> extern unsigned struct_sched_param_sz;
> extern unsigned struct_statfs_sz;
> extern unsigned struct_sockaddr_sz;
> @@ -412,6 +406,8 @@ extern int ptrace_pt_get_event_mask;
> extern int ptrace_pt_get_process_state;
> extern int ptrace_pt_set_siginfo;
> extern int ptrace_pt_get_siginfo;
> +extern int ptrace_pt_lwpstatus;
> +extern int ptrace_pt_lwpnext;
> extern int ptrace_piod_read_d;
> extern int ptrace_piod_write_d;
> extern int ptrace_piod_read_i;
> @@ -436,8 +432,17 @@ struct __sanitizer_ptrace_lwpinfo {
> int pl_event;
> };
>
> +struct __sanitizer_ptrace_lwpstatus {
> + __sanitizer_lwpid_t pl_lwpid;
> + __sanitizer_sigset_t pl_sigpend;
> + __sanitizer_sigset_t pl_sigmask;
> + char pl_name[20];
> + void *pl_private;
> +};
> +
> extern unsigned struct_ptrace_ptrace_io_desc_struct_sz;
> extern unsigned struct_ptrace_ptrace_lwpinfo_struct_sz;
> +extern unsigned struct_ptrace_ptrace_lwpstatus_struct_sz;
> extern unsigned struct_ptrace_ptrace_event_struct_sz;
> extern unsigned struct_ptrace_ptrace_siginfo_struct_sz;
>
> @@ -862,6 +867,7 @@ extern unsigned struct_nvmm_ioc_machine_destroy_sz;
> extern unsigned struct_nvmm_ioc_machine_configure_sz;
> extern unsigned struct_nvmm_ioc_vcpu_create_sz;
> extern unsigned struct_nvmm_ioc_vcpu_destroy_sz;
> +extern unsigned struct_nvmm_ioc_vcpu_configure_sz;
> extern unsigned struct_nvmm_ioc_vcpu_setstate_sz;
> extern unsigned struct_nvmm_ioc_vcpu_getstate_sz;
> extern unsigned struct_nvmm_ioc_vcpu_inject_sz;
> @@ -1611,6 +1617,7 @@ extern unsigned IOCTL_NVMM_IOC_MACHINE_DESTROY;
> extern unsigned IOCTL_NVMM_IOC_MACHINE_CONFIGURE;
> extern unsigned IOCTL_NVMM_IOC_VCPU_CREATE;
> extern unsigned IOCTL_NVMM_IOC_VCPU_DESTROY;
> +extern unsigned IOCTL_NVMM_IOC_VCPU_CONFIGURE;
> extern unsigned IOCTL_NVMM_IOC_VCPU_SETSTATE;
> extern unsigned IOCTL_NVMM_IOC_VCPU_GETSTATE;
> extern unsigned IOCTL_NVMM_IOC_VCPU_INJECT;
> @@ -1685,6 +1692,7 @@ extern unsigned IOCTL_IOC_NPF_STATS;
> extern unsigned IOCTL_IOC_NPF_SAVE;
> extern unsigned IOCTL_IOC_NPF_RULE;
> extern unsigned IOCTL_IOC_NPF_CONN_LOOKUP;
> +extern unsigned IOCTL_IOC_NPF_TABLE_REPLACE;
> extern unsigned IOCTL_PPPOESETPARMS;
> extern unsigned IOCTL_PPPOEGETPARMS;
> extern unsigned IOCTL_PPPOEGETSESSION;
> @@ -2406,6 +2414,9 @@ struct __sanitizer_cdbw {
>
> #define SIGACTION_SYMNAME __sigaction14
>
> +// Compat with 9.0
> +extern unsigned struct_statvfs90_sz;
> +
> #endif // SANITIZER_NETBSD
>
> #endif
> diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_openbsd.cpp b/libsanitizer/sanitizer_common/sanitizer_platform_limits_openbsd.cpp
> index 12515626ce5..1420ecbfa56 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_openbsd.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_openbsd.cpp
> @@ -72,6 +72,7 @@ unsigned struct_passwd_sz = sizeof(struct passwd);
> unsigned struct_group_sz = sizeof(struct group);
> unsigned siginfo_t_sz = sizeof(siginfo_t);
> unsigned struct_sigaction_sz = sizeof(struct sigaction);
> +unsigned struct_stack_t_sz = sizeof(stack_t);
> unsigned struct_itimerval_sz = sizeof(struct itimerval);
> unsigned pthread_t_sz = sizeof(pthread_t);
> unsigned pthread_mutex_t_sz = sizeof(pthread_mutex_t);
> diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_openbsd.h b/libsanitizer/sanitizer_common/sanitizer_platform_limits_openbsd.h
> index 6d8b062716b..8a194872360 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_openbsd.h
> +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_openbsd.h
> @@ -50,6 +50,7 @@ extern unsigned struct_timezone_sz;
> extern unsigned struct_tms_sz;
> extern unsigned struct_itimerspec_sz;
> extern unsigned struct_sigevent_sz;
> +extern unsigned struct_stack_t_sz;
> extern unsigned struct_statfs_sz;
> extern unsigned struct_sockaddr_sz;
>
> diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp
> index aa845df4dde..e71515f12e9 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp
> @@ -179,6 +179,7 @@ namespace __sanitizer {
> unsigned struct_group_sz = sizeof(struct group);
> unsigned siginfo_t_sz = sizeof(siginfo_t);
> unsigned struct_sigaction_sz = sizeof(struct sigaction);
> + unsigned struct_stack_t_sz = sizeof(stack_t);
> unsigned struct_itimerval_sz = sizeof(struct itimerval);
> unsigned pthread_t_sz = sizeof(pthread_t);
> unsigned pthread_mutex_t_sz = sizeof(pthread_mutex_t);
> diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h
> index d82fd5e4005..f6c8a1450a9 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h
> +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h
> @@ -47,6 +47,7 @@ extern unsigned struct_timezone_sz;
> extern unsigned struct_tms_sz;
> extern unsigned struct_itimerspec_sz;
> extern unsigned struct_sigevent_sz;
> +extern unsigned struct_stack_t_sz;
> extern unsigned struct_sched_param_sz;
> extern unsigned struct_statfs64_sz;
> extern unsigned struct_regex_sz;
> @@ -82,7 +83,7 @@ const unsigned struct_kernel_stat64_sz = 104;
> #elif defined(__mips__)
> const unsigned struct_kernel_stat_sz = SANITIZER_ANDROID
> ? FIRST_32_SECOND_64(104, 128)
> - : FIRST_32_SECOND_64(144, 216);
> + : FIRST_32_SECOND_64(160, 216);
> const unsigned struct_kernel_stat64_sz = 104;
> #elif defined(__s390__) && !defined(__s390x__)
> const unsigned struct_kernel_stat_sz = 64;
> diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_solaris.cpp b/libsanitizer/sanitizer_common/sanitizer_platform_limits_solaris.cpp
> index 9717d98ebf1..6ec1a1bdd11 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_solaris.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_solaris.cpp
> @@ -72,6 +72,7 @@ namespace __sanitizer {
> unsigned struct_group_sz = sizeof(struct group);
> unsigned siginfo_t_sz = sizeof(siginfo_t);
> unsigned struct_sigaction_sz = sizeof(struct sigaction);
> + unsigned struct_stack_t_sz = sizeof(stack_t);
> unsigned struct_itimerval_sz = sizeof(struct itimerval);
> unsigned pthread_t_sz = sizeof(pthread_t);
> unsigned pthread_mutex_t_sz = sizeof(pthread_mutex_t);
> diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_solaris.h b/libsanitizer/sanitizer_common/sanitizer_platform_limits_solaris.h
> index 77ae6e6a44d..85995e79792 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_solaris.h
> +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_solaris.h
> @@ -38,6 +38,7 @@ extern unsigned struct_timezone_sz;
> extern unsigned struct_tms_sz;
> extern unsigned struct_itimerspec_sz;
> extern unsigned struct_sigevent_sz;
> +extern unsigned struct_stack_t_sz;
> extern unsigned struct_sched_param_sz;
> extern unsigned struct_statfs64_sz;
> extern unsigned struct_statfs_sz;
> diff --git a/libsanitizer/sanitizer_common/sanitizer_posix.cpp b/libsanitizer/sanitizer_common/sanitizer_posix.cpp
> index d890a3a3177..e21661b42f8 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_posix.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_posix.cpp
> @@ -347,9 +347,17 @@ int GetNamedMappingFd(const char *name, uptr size, int *flags) {
> CHECK(internal_strlen(name) < sizeof(shmname) - 10);
> internal_snprintf(shmname, sizeof(shmname), "/dev/shm/%zu [%s]",
> internal_getpid(), name);
> + int o_cloexec = 0;
> +#if defined(O_CLOEXEC)
> + o_cloexec = O_CLOEXEC;
> +#endif
> int fd = ReserveStandardFds(
> - internal_open(shmname, O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, S_IRWXU));
> + internal_open(shmname, O_RDWR | O_CREAT | O_TRUNC | o_cloexec, S_IRWXU));
> CHECK_GE(fd, 0);
> + if (!o_cloexec) {
> + int res = fcntl(fd, F_SETFD, FD_CLOEXEC);
> + CHECK_EQ(0, res);
> + }
> int res = internal_ftruncate(fd, size);
> CHECK_EQ(0, res);
> res = internal_unlink(shmname);
> diff --git a/libsanitizer/sanitizer_common/sanitizer_posix.h b/libsanitizer/sanitizer_common/sanitizer_posix.h
> index 05fb0f63020..a1b49702da2 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_posix.h
> +++ b/libsanitizer/sanitizer_common/sanitizer_posix.h
> @@ -39,7 +39,7 @@ uptr internal_write(fd_t fd, const void *buf, uptr count);
>
> // Memory
> uptr internal_mmap(void *addr, uptr length, int prot, int flags,
> - int fd, OFF_T offset);
> + int fd, u64 offset);
> uptr internal_munmap(void *addr, uptr length);
> int internal_mprotect(void *addr, uptr length, int prot);
>
> @@ -63,7 +63,7 @@ uptr internal_ptrace(int request, int pid, void *addr, void *data);
> uptr internal_waitpid(int pid, int *status, int options);
>
> int internal_fork();
> -fd_t internal_spawn(const char *argv[], pid_t *pid);
> +fd_t internal_spawn(const char *argv[], const char *envp[], pid_t *pid);
>
> int internal_sysctl(const int *name, unsigned int namelen, void *oldp,
> uptr *oldlenp, const void *newp, uptr newlen);
> diff --git a/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp
> index 304b3a01a08..f920172c06d 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp
> @@ -426,7 +426,8 @@ void AdjustStackSize(void *attr_) {
> #endif // !SANITIZER_GO
>
> pid_t StartSubprocess(const char *program, const char *const argv[],
> - fd_t stdin_fd, fd_t stdout_fd, fd_t stderr_fd) {
> + const char *const envp[], fd_t stdin_fd, fd_t stdout_fd,
> + fd_t stderr_fd) {
> auto file_closer = at_scope_exit([&] {
> if (stdin_fd != kInvalidFd) {
> internal_close(stdin_fd);
> @@ -469,7 +470,8 @@ pid_t StartSubprocess(const char *program, const char *const argv[],
>
> for (int fd = sysconf(_SC_OPEN_MAX); fd > 2; fd--) internal_close(fd);
>
> - execv(program, const_cast<char **>(&argv[0]));
> + internal_execve(program, const_cast<char **>(&argv[0]),
> + const_cast<char *const *>(envp));
> internal__exit(1);
> }
>
> diff --git a/libsanitizer/sanitizer_common/sanitizer_procmaps.h b/libsanitizer/sanitizer_common/sanitizer_procmaps.h
> index d0e5245f84d..665ed45fa93 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_procmaps.h
> +++ b/libsanitizer/sanitizer_common/sanitizer_procmaps.h
> @@ -15,18 +15,19 @@
>
> #include "sanitizer_platform.h"
>
> -#if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || \
> - SANITIZER_OPENBSD || SANITIZER_MAC || SANITIZER_SOLARIS
> +#if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || \
> + SANITIZER_OPENBSD || SANITIZER_MAC || SANITIZER_SOLARIS || \
> + SANITIZER_FUCHSIA
>
> #include "sanitizer_common.h"
> #include "sanitizer_internal_defs.h"
> +#include "sanitizer_fuchsia.h"
> #include "sanitizer_linux.h"
> #include "sanitizer_mac.h"
> #include "sanitizer_mutex.h"
>
> namespace __sanitizer {
>
> -
> // Memory protection masks.
> static const uptr kProtectionRead = 1;
> static const uptr kProtectionWrite = 2;
> diff --git a/libsanitizer/sanitizer_common/sanitizer_procmaps_fuchsia.cpp b/libsanitizer/sanitizer_common/sanitizer_procmaps_fuchsia.cpp
> new file mode 100644
> index 00000000000..cc3e9be0645
> --- /dev/null
> +++ b/libsanitizer/sanitizer_common/sanitizer_procmaps_fuchsia.cpp
> @@ -0,0 +1,80 @@
> +//===-- sanitizer_procmaps_fuchsia.cpp
> +//----------------------------------------===//
> +//
> +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
> +// See https://llvm.org/LICENSE.txt for license information.
> +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
> +//
> +//===----------------------------------------------------------------------===//
> +//
> +// Information about the process mappings (Fuchsia-specific parts).
> +//===----------------------------------------------------------------------===//
> +
> +#include "sanitizer_platform.h"
> +#if SANITIZER_FUCHSIA
> +#include <zircon/process.h>
> +#include <zircon/syscalls.h>
> +
> +#include "sanitizer_common.h"
> +#include "sanitizer_procmaps.h"
> +
> +namespace __sanitizer {
> +
> +// The cache flag is ignored on Fuchsia because a process can always get this
> +// information via its process-self handle.
> +MemoryMappingLayout::MemoryMappingLayout(bool) { Reset(); }
> +
> +void MemoryMappingLayout::Reset() {
> + data_.data.clear();
> + data_.current = 0;
> +
> + size_t count;
> + zx_status_t status = _zx_object_get_info(
> + _zx_process_self(), ZX_INFO_PROCESS_MAPS, nullptr, 0, nullptr, &count);
> + if (status != ZX_OK) {
> + return;
> + }
> +
> + size_t filled;
> + do {
> + data_.data.resize(count);
> + status = _zx_object_get_info(
> + _zx_process_self(), ZX_INFO_PROCESS_MAPS, data_.data.data(),
> + count * sizeof(zx_info_maps_t), &filled, &count);
> + if (status != ZX_OK) {
> + data_.data.clear();
> + return;
> + }
> + } while (filled < count);
> +}
> +
> +MemoryMappingLayout::~MemoryMappingLayout() {}
> +
> +bool MemoryMappingLayout::Error() const { return data_.data.empty(); }
> +
> +bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) {
> + while (data_.current < data_.data.size()) {
> + const auto &entry = data_.data[data_.current++];
> + if (entry.type == ZX_INFO_MAPS_TYPE_MAPPING) {
> + segment->start = entry.base;
> + segment->end = entry.base + entry.size;
> + segment->offset = entry.u.mapping.vmo_offset;
> + const auto flags = entry.u.mapping.mmu_flags;
> + segment->protection =
> + ((flags & ZX_VM_PERM_READ) ? kProtectionRead : 0) |
> + ((flags & ZX_VM_PERM_WRITE) ? kProtectionWrite : 0) |
> + ((flags & ZX_VM_PERM_EXECUTE) ? kProtectionExecute : 0);
> + if (segment->filename && segment->filename_size > 0) {
> + uptr len = Min(sizeof(entry.name), segment->filename_size) - 1;
> + internal_strncpy(segment->filename, entry.name, len);
> + segment->filename[len] = 0;
> + }
> + return true;
> + }
> + }
> + return false;
> +}
> +
> +} // namespace __sanitizer
> +
> +#endif // SANITIZER_FUCHSIA
> diff --git a/libsanitizer/sanitizer_common/sanitizer_ptrauth.h b/libsanitizer/sanitizer_common/sanitizer_ptrauth.h
> new file mode 100644
> index 00000000000..4d0d96a64f6
> --- /dev/null
> +++ b/libsanitizer/sanitizer_common/sanitizer_ptrauth.h
> @@ -0,0 +1,21 @@
> +//===-- sanitizer_ptrauth.h -------------------------------------*- C++ -*-===//
> +//
> +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
> +// See https://llvm.org/LICENSE.txt for license information.
> +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
> +//
> +//===----------------------------------------------------------------------===//
> +
> +#ifndef SANITIZER_PTRAUTH_H
> +#define SANITIZER_PTRAUTH_H
> +
> +#if __has_feature(ptrauth_calls)
> +#include <ptrauth.h>
> +#else
> +// Copied from <ptrauth.h>
> +#define ptrauth_strip(__value, __key) __value
> +#define ptrauth_auth_data(__value, __old_key, __old_data) __value
> +#define ptrauth_string_discriminator(__string) ((int)0)
> +#endif
> +
> +#endif // SANITIZER_PTRAUTH_H
> diff --git a/libsanitizer/sanitizer_common/sanitizer_rtems.cpp b/libsanitizer/sanitizer_common/sanitizer_rtems.cpp
> index 0d2576c00ab..29bcfcfa6f1 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_rtems.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_rtems.cpp
> @@ -49,6 +49,10 @@ uptr internal_getpid() {
> return getpid();
> }
>
> +int internal_dlinfo(void *handle, int request, void *p) {
> + UNIMPLEMENTED();
> +}
> +
> bool FileExists(const char *filename) {
> struct stat st;
> if (stat(filename, &st))
> diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp b/libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp
> index ce75cbe5d26..ef14fb704ee 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp
> @@ -60,8 +60,8 @@ static inline uhwptr *GetCanonicFrame(uptr bp,
> // Nope, this does not look right either. This means the frame after next does
> // not have a valid frame pointer, but we can still extract the caller PC.
> // Unfortunately, there is no way to decide between GCC and LLVM frame
> - // layouts. Assume GCC.
> - return bp_prev - 1;
> + // layouts. Assume LLVM.
> + return bp_prev;
> #else
> return (uhwptr*)bp;
> #endif
> @@ -84,21 +84,14 @@ void BufferedStackTrace::UnwindFast(uptr pc, uptr bp, uptr stack_top,
> IsAligned((uptr)frame, sizeof(*frame)) &&
> size < max_depth) {
> #ifdef __powerpc__
> - // PowerPC ABIs specify that the return address is saved on the
> - // *caller's* stack frame. Thus we must dereference the back chain
> - // to find the caller frame before extracting it.
> + // PowerPC ABIs specify that the return address is saved at offset
> + // 16 of the *caller's* stack frame. Thus we must dereference the
> + // back chain to find the caller frame before extracting it.
> uhwptr *caller_frame = (uhwptr*)frame[0];
> if (!IsValidFrame((uptr)caller_frame, stack_top, bottom) ||
> !IsAligned((uptr)caller_frame, sizeof(uhwptr)))
> break;
> - // For most ABIs the offset where the return address is saved is two
> - // register sizes. The exception is the SVR4 ABI, which uses an
> - // offset of only one register size.
> -#ifdef _CALL_SYSV
> - uhwptr pc1 = caller_frame[1];
> -#else
> uhwptr pc1 = caller_frame[2];
> -#endif
> #elif defined(__s390__)
> uhwptr pc1 = frame[14];
> #else
> diff --git a/libsanitizer/sanitizer_common/sanitizer_stoptheworld_fuchsia.cpp b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_fuchsia.cpp
> new file mode 100644
> index 00000000000..3a246443ed9
> --- /dev/null
> +++ b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_fuchsia.cpp
> @@ -0,0 +1,42 @@
> +//===-- sanitizer_stoptheworld_fuchsia.cpp -------------------------------===//
> +//
> +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
> +// See https://llvm.org/LICENSE.txt for license information.
> +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
> +//
> +//===---------------------------------------------------------------------===//
> +//
> +// See sanitizer_stoptheworld.h for details.
> +//
> +//===---------------------------------------------------------------------===//
> +
> +#include "sanitizer_platform.h"
> +
> +#if SANITIZER_FUCHSIA
> +
> +#include <zircon/sanitizer.h>
> +
> +#include "sanitizer_stoptheworld.h"
> +
> +namespace __sanitizer {
> +
> +// The Fuchsia implementation stops the world but doesn't offer a real
> +// SuspendedThreadsList argument. This is enough for ASan's use case,
> +// and LSan does not use this API on Fuchsia.
> +void StopTheWorld(StopTheWorldCallback callback, void *argument) {
> + struct Params {
> + StopTheWorldCallback callback;
> + void *argument;
> + } params = {callback, argument};
> + __sanitizer_memory_snapshot(
> + nullptr, nullptr, nullptr, nullptr,
> + [](zx_status_t, void *data) {
> + auto params = reinterpret_cast<Params *>(data);
> + params->callback({}, params->argument);
> + },
> + ¶ms);
> +}
> +
> +} // namespace __sanitizer
> +
> +#endif // SANITIZER_FUCHSIA
> diff --git a/libsanitizer/sanitizer_common/sanitizer_stoptheworld_mac.cpp b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_mac.cpp
> index 9dffd21ecb7..6c577426ad5 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_stoptheworld_mac.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_mac.cpp
> @@ -50,7 +50,7 @@ struct RunThreadArgs {
> void *argument;
> };
>
> -void RunThread(void *arg) {
> +void *RunThread(void *arg) {
> struct RunThreadArgs *run_args = (struct RunThreadArgs *)arg;
> SuspendedThreadsListMac suspended_threads_list;
>
> @@ -59,7 +59,7 @@ void RunThread(void *arg) {
> kern_return_t err = task_threads(mach_task_self(), &threads, &num_threads);
> if (err != KERN_SUCCESS) {
> VReport(1, "Failed to get threads for task (errno %d).\n", err);
> - return;
> + return nullptr;
> }
>
> thread_t thread_self = mach_thread_self();
> @@ -76,6 +76,7 @@ void RunThread(void *arg) {
> for (unsigned int i = 0; i < num_suspended; ++i) {
> thread_resume(suspended_threads_list.GetThread(i));
> }
> + return nullptr;
> }
>
> void StopTheWorld(StopTheWorldCallback callback, void *argument) {
> @@ -159,7 +160,11 @@ PtraceRegistersStatus SuspendedThreadsListMac::GetRegistersAndSP(
> }
>
> internal_memcpy(buffer, ®s, sizeof(regs));
> +#if defined(__aarch64__) && defined(arm_thread_state64_get_sp)
> + *sp = arm_thread_state64_get_sp(regs);
> +#else
> *sp = regs.SP_REG;
> +#endif
>
> // On x86_64 and aarch64, we must account for the stack redzone, which is 128
> // bytes.
> diff --git a/libsanitizer/sanitizer_common/sanitizer_stoptheworld_netbsd_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_netbsd_libcdep.cpp
> index 5690d75097f..1ed21343254 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_stoptheworld_netbsd_libcdep.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_netbsd_libcdep.cpp
> @@ -120,10 +120,18 @@ bool ThreadSuspender::SuspendAllThreads() {
>
> VReport(2, "Attached to process %d.\n", pid_);
>
> +#ifdef PT_LWPNEXT
> + struct ptrace_lwpstatus pl;
> + int op = PT_LWPNEXT;
> +#else
> struct ptrace_lwpinfo pl;
> - int val;
> + int op = PT_LWPINFO;
> +#endif
> +
> pl.pl_lwpid = 0;
> - while ((val = ptrace(PT_LWPINFO, pid_, (void *)&pl, sizeof(pl))) != -1 &&
> +
> + int val;
> + while ((val = ptrace(op, pid_, (void *)&pl, sizeof(pl))) != -1 &&
> pl.pl_lwpid != 0) {
> suspended_threads_list_.Append(pl.pl_lwpid);
> VReport(2, "Appended thread %d in process %d.\n", pl.pl_lwpid, pid_);
> diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer.cpp
> index ce2ece5f4d5..0c4b84c767a 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer.cpp
> @@ -126,4 +126,10 @@ Symbolizer::SymbolizerScope::~SymbolizerScope() {
> sym_->end_hook_();
> }
>
> +void Symbolizer::LateInitializeTools() {
> + for (auto &tool : tools_) {
> + tool.LateInitialize();
> + }
> +}
> +
> } // namespace __sanitizer
> diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer.h b/libsanitizer/sanitizer_common/sanitizer_symbolizer.h
> index 51648e2d0e8..2476b0ea7bf 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer.h
> +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer.h
> @@ -209,6 +209,9 @@ class Symbolizer final {
> private:
> const Symbolizer *sym_;
> };
> +
> + // Calls `LateInitialize()` on all items in `tools_`.
> + void LateInitializeTools();
> };
>
> #ifdef SANITIZER_WINDOWS
> diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_internal.h b/libsanitizer/sanitizer_common/sanitizer_symbolizer_internal.h
> index c04797dd61b..e4c351e667b 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_internal.h
> +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_internal.h
> @@ -69,6 +69,11 @@ class SymbolizerTool {
> virtual const char *Demangle(const char *name) {
> return nullptr;
> }
> +
> + // Called during the LateInitialize phase of Sanitizer initialization.
> + // Usually this is a safe place to call code that might need to use user
> + // memory allocators.
> + virtual void LateInitialize() {}
> };
>
> // SymbolizerProcess encapsulates communication between the tool and
> @@ -86,6 +91,8 @@ class SymbolizerProcess {
> // Customizable by subclasses.
> virtual bool StartSymbolizerSubprocess();
> virtual bool ReadFromSymbolizer(char *buffer, uptr max_length);
> + // Return the environment to run the symbolizer in.
> + virtual char **GetEnvP() { return GetEnviron(); }
>
> private:
> virtual bool ReachedEndOfOutput(const char *buffer, uptr length) const {
> diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cpp
> index 3b19a6836ec..490c6fe89be 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cpp
> @@ -39,9 +39,9 @@ const char *ExtractToken(const char *str, const char *delims, char **result) {
> }
>
> const char *ExtractInt(const char *str, const char *delims, int *result) {
> - char *buff;
> + char *buff = nullptr;
> const char *ret = ExtractToken(str, delims, &buff);
> - if (buff != 0) {
> + if (buff) {
> *result = (int)internal_atoll(buff);
> }
> InternalFree(buff);
> @@ -49,9 +49,9 @@ const char *ExtractInt(const char *str, const char *delims, int *result) {
> }
>
> const char *ExtractUptr(const char *str, const char *delims, uptr *result) {
> - char *buff;
> + char *buff = nullptr;
> const char *ret = ExtractToken(str, delims, &buff);
> - if (buff != 0) {
> + if (buff) {
> *result = (uptr)internal_atoll(buff);
> }
> InternalFree(buff);
> @@ -59,9 +59,9 @@ const char *ExtractUptr(const char *str, const char *delims, uptr *result) {
> }
>
> const char *ExtractSptr(const char *str, const char *delims, sptr *result) {
> - char *buff;
> + char *buff = nullptr;
> const char *ret = ExtractToken(str, delims, &buff);
> - if (buff != 0) {
> + if (buff) {
> *result = (sptr)internal_atoll(buff);
> }
> InternalFree(buff);
> @@ -83,7 +83,7 @@ const char *ExtractTokenUpToDelimiter(const char *str, const char *delimiter,
>
> SymbolizedStack *Symbolizer::SymbolizePC(uptr addr) {
> BlockingMutexLock l(&mu_);
> - const char *module_name;
> + const char *module_name = nullptr;
> uptr module_offset;
> ModuleArch arch;
> SymbolizedStack *res = SymbolizedStack::New(addr);
> @@ -103,7 +103,7 @@ SymbolizedStack *Symbolizer::SymbolizePC(uptr addr) {
>
> bool Symbolizer::SymbolizeData(uptr addr, DataInfo *info) {
> BlockingMutexLock l(&mu_);
> - const char *module_name;
> + const char *module_name = nullptr;
> uptr module_offset;
> ModuleArch arch;
> if (!FindModuleNameAndOffsetForAddress(addr, &module_name, &module_offset,
> @@ -124,7 +124,7 @@ bool Symbolizer::SymbolizeData(uptr addr, DataInfo *info) {
>
> bool Symbolizer::SymbolizeFrame(uptr addr, FrameInfo *info) {
> BlockingMutexLock l(&mu_);
> - const char *module_name;
> + const char *module_name = nullptr;
> if (!FindModuleNameAndOffsetForAddress(
> addr, &module_name, &info->module_offset, &info->module_arch))
> return false;
> @@ -175,7 +175,7 @@ bool Symbolizer::FindModuleNameAndOffsetForAddress(uptr address,
> uptr *module_offset,
> ModuleArch *module_arch) {
> const LoadedModule *module = FindModuleForAddress(address);
> - if (module == nullptr)
> + if (!module)
> return false;
> *module_name = module->full_name();
> *module_offset = address - module->base_address();
> @@ -292,7 +292,7 @@ LLVMSymbolizer::LLVMSymbolizer(const char *path, LowLevelAllocator *allocator)
> // Windows, so extract tokens from the right hand side first. The column info is
> // also optional.
> static const char *ParseFileLineInfo(AddressInfo *info, const char *str) {
> - char *file_line_info = 0;
> + char *file_line_info = nullptr;
> str = ExtractToken(str, "\n", &file_line_info);
> CHECK(file_line_info);
>
> @@ -323,7 +323,7 @@ void ParseSymbolizePCOutput(const char *str, SymbolizedStack *res) {
> bool top_frame = true;
> SymbolizedStack *last = res;
> while (true) {
> - char *function_name = 0;
> + char *function_name = nullptr;
> str = ExtractToken(str, "\n", &function_name);
> CHECK(function_name);
> if (function_name[0] == '\0') {
> @@ -402,32 +402,29 @@ bool LLVMSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) {
> AddressInfo *info = &stack->info;
> const char *buf = FormatAndSendCommand(
> "CODE", info->module, info->module_offset, info->module_arch);
> - if (buf) {
> - ParseSymbolizePCOutput(buf, stack);
> - return true;
> - }
> - return false;
> + if (!buf)
> + return false;
> + ParseSymbolizePCOutput(buf, stack);
> + return true;
> }
>
> bool LLVMSymbolizer::SymbolizeData(uptr addr, DataInfo *info) {
> const char *buf = FormatAndSendCommand(
> "DATA", info->module, info->module_offset, info->module_arch);
> - if (buf) {
> - ParseSymbolizeDataOutput(buf, info);
> - info->start += (addr - info->module_offset); // Add the base address.
> - return true;
> - }
> - return false;
> + if (!buf)
> + return false;
> + ParseSymbolizeDataOutput(buf, info);
> + info->start += (addr - info->module_offset); // Add the base address.
> + return true;
> }
>
> bool LLVMSymbolizer::SymbolizeFrame(uptr addr, FrameInfo *info) {
> const char *buf = FormatAndSendCommand(
> "FRAME", info->module, info->module_offset, info->module_arch);
> - if (buf) {
> - ParseSymbolizeFrameOutput(buf, &info->locals);
> - return true;
> - }
> - return false;
> + if (!buf)
> + return false;
> + ParseSymbolizeFrameOutput(buf, &info->locals);
> + return true;
> }
>
> const char *LLVMSymbolizer::FormatAndSendCommand(const char *command_prefix,
> @@ -435,21 +432,21 @@ const char *LLVMSymbolizer::FormatAndSendCommand(const char *command_prefix,
> uptr module_offset,
> ModuleArch arch) {
> CHECK(module_name);
> - if (arch == kModuleArchUnknown) {
> - if (internal_snprintf(buffer_, kBufferSize, "%s \"%s\" 0x%zx\n",
> - command_prefix, module_name,
> - module_offset) >= static_cast<int>(kBufferSize)) {
> - Report("WARNING: Command buffer too small");
> - return nullptr;
> - }
> - } else {
> - if (internal_snprintf(buffer_, kBufferSize, "%s \"%s:%s\" 0x%zx\n",
> - command_prefix, module_name, ModuleArchToString(arch),
> - module_offset) >= static_cast<int>(kBufferSize)) {
> - Report("WARNING: Command buffer too small");
> - return nullptr;
> - }
> + int size_needed = 0;
> + if (arch == kModuleArchUnknown)
> + size_needed = internal_snprintf(buffer_, kBufferSize, "%s \"%s\" 0x%zx\n",
> + command_prefix, module_name, module_offset);
> + else
> + size_needed = internal_snprintf(buffer_, kBufferSize,
> + "%s \"%s:%s\" 0x%zx\n", command_prefix,
> + module_name, ModuleArchToString(arch),
> + module_offset);
> +
> + if (size_needed >= static_cast<int>(kBufferSize)) {
> + Report("WARNING: Command buffer too small");
> + return nullptr;
> }
> +
> return symbolizer_process_->SendCommand(buffer_);
> }
>
> @@ -492,16 +489,16 @@ const char *SymbolizerProcess::SendCommand(const char *command) {
> Report("WARNING: Failed to use and restart external symbolizer!\n");
> failed_to_start_ = true;
> }
> - return 0;
> + return nullptr;
> }
>
> const char *SymbolizerProcess::SendCommandImpl(const char *command) {
> if (input_fd_ == kInvalidFd || output_fd_ == kInvalidFd)
> - return 0;
> + return nullptr;
> if (!WriteToSymbolizer(command, internal_strlen(command)))
> - return 0;
> + return nullptr;
> if (!ReadFromSymbolizer(buffer_, kBufferSize))
> - return 0;
> + return nullptr;
> return buffer_;
> }
>
> diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.cpp
> index a619ed092f0..cc233408d0c 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.cpp
> @@ -20,6 +20,7 @@
>
> #include <dlfcn.h>
> #include <errno.h>
> +#include <mach/mach.h>
> #include <stdlib.h>
> #include <sys/wait.h>
> #include <unistd.h>
> @@ -31,6 +32,9 @@ bool DlAddrSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) {
> Dl_info info;
> int result = dladdr((const void *)addr, &info);
> if (!result) return false;
> +
> + CHECK(addr >= reinterpret_cast<uptr>(info.dli_saddr));
> + stack->info.function_offset = addr - reinterpret_cast<uptr>(info.dli_saddr);
> const char *demangled = DemangleSwiftAndCXX(info.dli_sname);
> if (!demangled) return false;
> stack->info.function = internal_strdup(demangled);
> @@ -47,18 +51,65 @@ bool DlAddrSymbolizer::SymbolizeData(uptr addr, DataInfo *datainfo) {
> return true;
> }
>
> +#define K_ATOS_ENV_VAR "__check_mach_ports_lookup"
> +
> +// This cannot live in `AtosSymbolizerProcess` because instances of that object
> +// are allocated by the internal allocator which under ASan is poisoned with
> +// kAsanInternalHeapMagic.
> +static char kAtosMachPortEnvEntry[] = K_ATOS_ENV_VAR "=000000000000000";
> +
> class AtosSymbolizerProcess : public SymbolizerProcess {
> public:
> - explicit AtosSymbolizerProcess(const char *path, pid_t parent_pid)
> + explicit AtosSymbolizerProcess(const char *path)
> : SymbolizerProcess(path, /*use_posix_spawn*/ true) {
> - // Put the string command line argument in the object so that it outlives
> - // the call to GetArgV.
> - internal_snprintf(pid_str_, sizeof(pid_str_), "%d", parent_pid);
> + pid_str_[0] = '\0';
> + }
> +
> + void LateInitialize() {
> + if (SANITIZER_IOSSIM) {
> + // `putenv()` may call malloc/realloc so it is only safe to do this
> + // during LateInitialize() or later (i.e. we can't do this in the
> + // constructor). We also can't do this in `StartSymbolizerSubprocess()`
> + // because in TSan we switch allocators when we're symbolizing.
> + // We use `putenv()` rather than `setenv()` so that we can later directly
> + // write into the storage without LibC getting involved to change what the
> + // variable is set to
> + int result = putenv(kAtosMachPortEnvEntry);
> + CHECK_EQ(result, 0);
> + }
> }
>
> private:
> bool StartSymbolizerSubprocess() override {
> // Configure sandbox before starting atos process.
> +
> + // Put the string command line argument in the object so that it outlives
> + // the call to GetArgV.
> + internal_snprintf(pid_str_, sizeof(pid_str_), "%d", internal_getpid());
> +
> + if (SANITIZER_IOSSIM) {
> + // `atos` in the simulator is restricted in its ability to retrieve the
> + // task port for the target process (us) so we need to do extra work
> + // to pass our task port to it.
> + mach_port_t ports[]{mach_task_self()};
> + kern_return_t ret =
> + mach_ports_register(mach_task_self(), ports, /*count=*/1);
> + CHECK_EQ(ret, KERN_SUCCESS);
> +
> + // Set environment variable that signals to `atos` that it should look
> + // for our task port. We can't call `setenv()` here because it might call
> + // malloc/realloc. To avoid that we instead update the
> + // `mach_port_env_var_entry_` variable with our current PID.
> + uptr count = internal_snprintf(kAtosMachPortEnvEntry,
> + sizeof(kAtosMachPortEnvEntry),
> + K_ATOS_ENV_VAR "=%s", pid_str_);
> + CHECK_GE(count, sizeof(K_ATOS_ENV_VAR) + internal_strlen(pid_str_));
> + // Document our assumption but without calling `getenv()` in normal
> + // builds.
> + DCHECK(getenv(K_ATOS_ENV_VAR));
> + DCHECK_EQ(internal_strcmp(getenv(K_ATOS_ENV_VAR), pid_str_), 0);
> + }
> +
> return SymbolizerProcess::StartSymbolizerSubprocess();
> }
>
> @@ -82,8 +133,14 @@ class AtosSymbolizerProcess : public SymbolizerProcess {
> }
>
> char pid_str_[16];
> + // Space for `\0` in `K_ATOS_ENV_VAR` is reused for `=`.
> + static_assert(sizeof(kAtosMachPortEnvEntry) ==
> + (sizeof(K_ATOS_ENV_VAR) + sizeof(pid_str_)),
> + "sizes should match");
> };
>
> +#undef K_ATOS_ENV_VAR
> +
> static bool ParseCommandOutput(const char *str, uptr addr, char **out_name,
> char **out_module, char **out_file, uptr *line,
> uptr *start_address) {
> @@ -135,7 +192,7 @@ static bool ParseCommandOutput(const char *str, uptr addr, char **out_name,
> }
>
> AtosSymbolizer::AtosSymbolizer(const char *path, LowLevelAllocator *allocator)
> - : process_(new(*allocator) AtosSymbolizerProcess(path, getpid())) {}
> + : process_(new (*allocator) AtosSymbolizerProcess(path)) {}
>
> bool AtosSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) {
> if (!process_) return false;
> @@ -145,12 +202,29 @@ bool AtosSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) {
> const char *buf = process_->SendCommand(command);
> if (!buf) return false;
> uptr line;
> + uptr start_address = AddressInfo::kUnknown;
> if (!ParseCommandOutput(buf, addr, &stack->info.function, &stack->info.module,
> - &stack->info.file, &line, nullptr)) {
> + &stack->info.file, &line, &start_address)) {
> process_ = nullptr;
> return false;
> }
> stack->info.line = (int)line;
> +
> + if (start_address == AddressInfo::kUnknown) {
> + // Fallback to dladdr() to get function start address if atos doesn't report
> + // it.
> + Dl_info info;
> + int result = dladdr((const void *)addr, &info);
> + if (result)
> + start_address = reinterpret_cast<uptr>(info.dli_saddr);
> + }
> +
> + // Only assig to `function_offset` if we were able to get the function's
> + // start address.
> + if (start_address != AddressInfo::kUnknown) {
> + CHECK(addr >= start_address);
> + stack->info.function_offset = addr - start_address;
> + }
> return true;
> }
>
> @@ -168,6 +242,8 @@ bool AtosSymbolizer::SymbolizeData(uptr addr, DataInfo *info) {
> return true;
> }
>
> +void AtosSymbolizer::LateInitialize() { process_->LateInitialize(); }
> +
> } // namespace __sanitizer
>
> #endif // SANITIZER_MAC
> diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.h b/libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.h
> index 68521375e64..8996131fc13 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.h
> +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.h
> @@ -35,6 +35,7 @@ class AtosSymbolizer : public SymbolizerTool {
>
> bool SymbolizePC(uptr addr, SymbolizedStack *stack) override;
> bool SymbolizeData(uptr addr, DataInfo *info) override;
> + void LateInitialize() override;
>
> private:
> AtosSymbolizerProcess *process_;
> diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_markup.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_markup.cpp
> index 57b4d0c9d96..2963af95360 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_markup.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_markup.cpp
> @@ -94,7 +94,9 @@ Symbolizer *Symbolizer::PlatformInit() {
> return new (symbolizer_allocator_) Symbolizer({});
> }
>
> -void Symbolizer::LateInitialize() { Symbolizer::GetOrInit(); }
> +void Symbolizer::LateInitialize() {
> + Symbolizer::GetOrInit()->LateInitializeTools();
> +}
>
> void StartReportDeadlySignal() {}
> void ReportDeadlySignal(const SignalContext &sig, u32 tid,
> diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp
> index c123ecb1120..d7b931bc237 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp
> @@ -151,9 +151,19 @@ bool SymbolizerProcess::StartSymbolizerSubprocess() {
> GetArgV(path_, argv);
> pid_t pid;
>
> + // Report how symbolizer is being launched for debugging purposes.
> + if (Verbosity() >= 3) {
> + // Only use `Report` for first line so subsequent prints don't get prefixed
> + // with current PID.
> + Report("Launching Symbolizer process: ");
> + for (unsigned index = 0; index < kArgVMax && argv[index]; ++index)
> + Printf("%s ", argv[index]);
> + Printf("\n");
> + }
> +
> if (use_posix_spawn_) {
> #if SANITIZER_MAC
> - fd_t fd = internal_spawn(argv, &pid);
> + fd_t fd = internal_spawn(argv, const_cast<const char **>(GetEnvP()), &pid);
> if (fd == kInvalidFd) {
> Report("WARNING: failed to spawn external symbolizer (errno: %d)\n",
> errno);
> @@ -173,7 +183,7 @@ bool SymbolizerProcess::StartSymbolizerSubprocess() {
> return false;
> }
>
> - pid = StartSubprocess(path_, argv, /* stdin */ outfd[0],
> + pid = StartSubprocess(path_, argv, GetEnvP(), /* stdin */ outfd[0],
> /* stdout */ infd[1]);
> if (pid < 0) {
> internal_close(infd[0]);
> @@ -478,7 +488,7 @@ Symbolizer *Symbolizer::PlatformInit() {
> }
>
> void Symbolizer::LateInitialize() {
> - Symbolizer::GetOrInit();
> + Symbolizer::GetOrInit()->LateInitializeTools();
> InitializeSwiftDemangler();
> }
>
> diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cpp
> index 2808779156e..373437e7ee2 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cpp
> @@ -310,7 +310,7 @@ Symbolizer *Symbolizer::PlatformInit() {
> }
>
> void Symbolizer::LateInitialize() {
> - Symbolizer::GetOrInit();
> + Symbolizer::GetOrInit()->LateInitializeTools();
> }
>
> } // namespace __sanitizer
> diff --git a/libsanitizer/sanitizer_common/sanitizer_syscalls_netbsd.inc b/libsanitizer/sanitizer_common/sanitizer_syscalls_netbsd.inc
> index 69e59871874..02b7e11b167 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_syscalls_netbsd.inc
> +++ b/libsanitizer/sanitizer_common/sanitizer_syscalls_netbsd.inc
> @@ -42,7 +42,7 @@
> // DO NOT EDIT! THIS FILE HAS BEEN GENERATED!
> //
> // Generated with: generate_netbsd_syscalls.awk
> -// Generated date: 2019-11-01
> +// Generated date: 2019-12-24
> // Generated from: syscalls.master,v 1.296 2019/09/22 22:59:39 christos Exp
> //
> //===----------------------------------------------------------------------===//
> @@ -323,6 +323,16 @@ PRE_SYSCALL(ptrace)
> PRE_READ(addr_, struct_ptrace_ptrace_siginfo_struct_sz);
> } else if (req_ == ptrace_pt_get_siginfo) {
> PRE_WRITE(addr_, struct_ptrace_ptrace_siginfo_struct_sz);
> + } else if (req_ == ptrace_pt_lwpstatus) {
> + struct __sanitizer_ptrace_lwpstatus *addr =
> + (struct __sanitizer_ptrace_lwpstatus *)addr_;
> + PRE_READ(&addr->pl_lwpid, sizeof(__sanitizer_lwpid_t));
> + PRE_WRITE(addr, struct_ptrace_ptrace_lwpstatus_struct_sz);
> + } else if (req_ == ptrace_pt_lwpnext) {
> + struct __sanitizer_ptrace_lwpstatus *addr =
> + (struct __sanitizer_ptrace_lwpstatus *)addr_;
> + PRE_READ(&addr->pl_lwpid, sizeof(__sanitizer_lwpid_t));
> + PRE_WRITE(addr, struct_ptrace_ptrace_lwpstatus_struct_sz);
> } else if (req_ == ptrace_pt_setregs) {
> PRE_READ(addr_, struct_ptrace_reg_struct_sz);
> } else if (req_ == ptrace_pt_getregs) {
> @@ -366,6 +376,16 @@ POST_SYSCALL(ptrace)
> POST_READ(addr_, struct_ptrace_ptrace_siginfo_struct_sz);
> } else if (req_ == ptrace_pt_get_siginfo) {
> POST_WRITE(addr_, struct_ptrace_ptrace_siginfo_struct_sz);
> + } else if (req_ == ptrace_pt_lwpstatus) {
> + struct __sanitizer_ptrace_lwpstatus *addr =
> + (struct __sanitizer_ptrace_lwpstatus *)addr_;
> + POST_READ(&addr->pl_lwpid, sizeof(__sanitizer_lwpid_t));
> + POST_WRITE(addr, struct_ptrace_ptrace_lwpstatus_struct_sz);
> + } else if (req_ == ptrace_pt_lwpnext) {
> + struct __sanitizer_ptrace_lwpstatus *addr =
> + (struct __sanitizer_ptrace_lwpstatus *)addr_;
> + POST_READ(&addr->pl_lwpid, sizeof(__sanitizer_lwpid_t));
> + POST_WRITE(addr, struct_ptrace_ptrace_lwpstatus_struct_sz);
> } else if (req_ == ptrace_pt_setregs) {
> POST_READ(addr_, struct_ptrace_reg_struct_sz);
> } else if (req_ == ptrace_pt_getregs) {
> diff --git a/libsanitizer/sanitizer_common/sanitizer_win.cpp b/libsanitizer/sanitizer_common/sanitizer_win.cpp
> index 36dde49d870..fca15beb616 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_win.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_win.cpp
> @@ -94,6 +94,10 @@ uptr internal_getpid() {
> return GetProcessId(GetCurrentProcess());
> }
>
> +int internal_dlinfo(void *handle, int request, void *p) {
> + UNIMPLEMENTED();
> +}
> +
> // In contrast to POSIX, on Windows GetCurrentThreadId()
> // returns a system-unique identifier.
> tid_t GetTid() {
> @@ -787,7 +791,7 @@ uptr GetRSS() {
> return counters.WorkingSetSize;
> }
>
> -void *internal_start_thread(void (*func)(void *arg), void *arg) { return 0; }
> +void *internal_start_thread(void *(*func)(void *arg), void *arg) { return 0; }
> void internal_join_thread(void *th) { }
>
> // ---------------------- BlockingMutex ---------------- {{{1
> @@ -1060,7 +1064,8 @@ char **GetEnviron() {
> }
>
> pid_t StartSubprocess(const char *program, const char *const argv[],
> - fd_t stdin_fd, fd_t stdout_fd, fd_t stderr_fd) {
> + const char *const envp[], fd_t stdin_fd, fd_t stdout_fd,
> + fd_t stderr_fd) {
> // FIXME: implement on this platform
> // Should be implemented based on
> // SymbolizerProcess::StarAtSymbolizerSubprocess
> diff --git a/libsanitizer/tsan/tsan_clock.cpp b/libsanitizer/tsan/tsan_clock.cpp
> index 4b7aa0653da..c91b29cb22b 100644
> --- a/libsanitizer/tsan/tsan_clock.cpp
> +++ b/libsanitizer/tsan/tsan_clock.cpp
> @@ -30,6 +30,14 @@
> // dst->clock[i] = max(dst->clock[i], clock[i]);
> // }
> //
> +// void ThreadClock::releaseStoreAcquire(SyncClock *sc) const {
> +// for (int i = 0; i < kMaxThreads; i++) {
> +// tmp = clock[i];
> +// clock[i] = max(clock[i], sc->clock[i]);
> +// sc->clock[i] = tmp;
> +// }
> +// }
> +//
> // void ThreadClock::ReleaseStore(SyncClock *dst) const {
> // for (int i = 0; i < kMaxThreads; i++)
> // dst->clock[i] = clock[i];
> @@ -107,13 +115,14 @@ static void UnrefClockBlock(ClockCache *c, u32 idx, uptr blocks) {
> ThreadClock::ThreadClock(unsigned tid, unsigned reused)
> : tid_(tid)
> , reused_(reused + 1) // 0 has special meaning
> + , last_acquire_()
> + , global_acquire_()
> , cached_idx_()
> , cached_size_()
> , cached_blocks_() {
> CHECK_LT(tid, kMaxTidInClock);
> CHECK_EQ(reused_, ((u64)reused_ << kClkBits) >> kClkBits);
> nclk_ = tid_ + 1;
> - last_acquire_ = 0;
> internal_memset(clk_, 0, sizeof(clk_));
> }
>
> @@ -177,6 +186,49 @@ void ThreadClock::acquire(ClockCache *c, SyncClock *src) {
> }
> }
>
> +void ThreadClock::releaseStoreAcquire(ClockCache *c, SyncClock *sc) {
> + DCHECK_LE(nclk_, kMaxTid);
> + DCHECK_LE(sc->size_, kMaxTid);
> +
> + if (sc->size_ == 0) {
> + // ReleaseStore will correctly set release_store_tid_,
> + // which can be important for future operations.
> + ReleaseStore(c, sc);
> + return;
> + }
> +
> + nclk_ = max(nclk_, (uptr) sc->size_);
> +
> + // Check if we need to resize sc.
> + if (sc->size_ < nclk_)
> + sc->Resize(c, nclk_);
> +
> + bool acquired = false;
> +
> + sc->Unshare(c);
> + // Update sc->clk_.
> + sc->FlushDirty();
> + uptr i = 0;
> + for (ClockElem &ce : *sc) {
> + u64 tmp = clk_[i];
> + if (clk_[i] < ce.epoch) {
> + clk_[i] = ce.epoch;
> + acquired = true;
> + }
> + ce.epoch = tmp;
> + ce.reused = 0;
> + i++;
> + }
> + sc->release_store_tid_ = kInvalidTid;
> + sc->release_store_reused_ = 0;
> +
> + if (acquired) {
> + CPP_STAT_INC(StatClockAcquiredSomething);
> + last_acquire_ = clk_[tid_];
> + ResetCached(c);
> + }
> +}
> +
> void ThreadClock::release(ClockCache *c, SyncClock *dst) {
> DCHECK_LE(nclk_, kMaxTid);
> DCHECK_LE(dst->size_, kMaxTid);
> @@ -196,7 +248,7 @@ void ThreadClock::release(ClockCache *c, SyncClock *dst) {
> // Check if we had not acquired anything from other threads
> // since the last release on dst. If so, we need to update
> // only dst->elem(tid_).
> - if (dst->elem(tid_).epoch > last_acquire_) {
> + if (!HasAcquiredAfterRelease(dst)) {
> UpdateCurrentThread(c, dst);
> if (dst->release_store_tid_ != tid_ ||
> dst->release_store_reused_ != reused_)
> @@ -222,8 +274,6 @@ void ThreadClock::release(ClockCache *c, SyncClock *dst) {
> // Clear 'acquired' flag in the remaining elements.
> if (nclk_ < dst->size_)
> CPP_STAT_INC(StatClockReleaseClearTail);
> - for (uptr i = nclk_; i < dst->size_; i++)
> - dst->elem(i).reused = 0;
> dst->release_store_tid_ = kInvalidTid;
> dst->release_store_reused_ = 0;
> // If we've acquired dst, remember this fact,
> @@ -269,7 +319,7 @@ void ThreadClock::ReleaseStore(ClockCache *c, SyncClock *dst) {
>
> if (dst->release_store_tid_ == tid_ &&
> dst->release_store_reused_ == reused_ &&
> - dst->elem(tid_).epoch > last_acquire_) {
> + !HasAcquiredAfterRelease(dst)) {
> CPP_STAT_INC(StatClockStoreFast);
> UpdateCurrentThread(c, dst);
> return;
> @@ -351,6 +401,14 @@ bool ThreadClock::IsAlreadyAcquired(const SyncClock *src) const {
> return true;
> }
>
> +// Checks whether the current thread has acquired anything
> +// from other clocks after releasing to dst (directly or indirectly).
> +bool ThreadClock::HasAcquiredAfterRelease(const SyncClock *dst) const {
> + const u64 my_epoch = dst->elem(tid_).epoch;
> + return my_epoch <= last_acquire_ ||
> + my_epoch <= atomic_load_relaxed(&global_acquire_);
> +}
> +
> // Sets a single element in the vector clock.
> // This function is called only from weird places like AcquireGlobal.
> void ThreadClock::set(ClockCache *c, unsigned tid, u64 v) {
> diff --git a/libsanitizer/tsan/tsan_clock.h b/libsanitizer/tsan/tsan_clock.h
> index 6a1d15a2a16..736cdae06ba 100644
> --- a/libsanitizer/tsan/tsan_clock.h
> +++ b/libsanitizer/tsan/tsan_clock.h
> @@ -134,10 +134,12 @@ class ThreadClock {
> uptr size() const;
>
> void acquire(ClockCache *c, SyncClock *src);
> + void releaseStoreAcquire(ClockCache *c, SyncClock *src);
> void release(ClockCache *c, SyncClock *dst);
> void acq_rel(ClockCache *c, SyncClock *dst);
> void ReleaseStore(ClockCache *c, SyncClock *dst);
> void ResetCached(ClockCache *c);
> + void NoteGlobalAcquire(u64 v);
>
> void DebugReset();
> void DebugDump(int(*printf)(const char *s, ...));
> @@ -150,6 +152,53 @@ class ThreadClock {
> // Current thread time when it acquired something from other threads.
> u64 last_acquire_;
>
> + // Last time another thread has done a global acquire of this thread's clock.
> + // It helps to avoid problem described in:
> + // https://github.com/golang/go/issues/39186
> + // See test/tsan/java_finalizer2.cpp for a regression test.
> + // Note the failuire is _extremely_ hard to hit, so if you are trying
> + // to reproduce it, you may want to run something like:
> + // $ go get golang.org/x/tools/cmd/stress
> + // $ stress -p=64 ./a.out
> + //
> + // The crux of the problem is roughly as follows.
> + // A number of O(1) optimizations in the clocks algorithm assume proper
> + // transitive cumulative propagation of clock values. The AcquireGlobal
> + // operation may produce an inconsistent non-linearazable view of
> + // thread clocks. Namely, it may acquire a later value from a thread
> + // with a higher ID, but fail to acquire an earlier value from a thread
> + // with a lower ID. If a thread that executed AcquireGlobal then releases
> + // to a sync clock, it will spoil the sync clock with the inconsistent
> + // values. If another thread later releases to the sync clock, the optimized
> + // algorithm may break.
> + //
> + // The exact sequence of events that leads to the failure.
> + // - thread 1 executes AcquireGlobal
> + // - thread 1 acquires value 1 for thread 2
> + // - thread 2 increments clock to 2
> + // - thread 2 releases to sync object 1
> + // - thread 3 at time 1
> + // - thread 3 acquires from sync object 1
> + // - thread 3 increments clock to 2
> + // - thread 1 acquires value 2 for thread 3
> + // - thread 1 releases to sync object 2
> + // - sync object 2 clock has 1 for thread 2 and 2 for thread 3
> + // - thread 3 releases to sync object 2
> + // - thread 3 sees value 2 in the clock for itself
> + // and decides that it has already released to the clock
> + // and did not acquire anything from other threads after that
> + // (the last_acquire_ check in release operation)
> + // - thread 3 does not update the value for thread 2 in the clock from 1 to 2
> + // - thread 4 acquires from sync object 2
> + // - thread 4 detects a false race with thread 2
> + // as it should have been synchronized with thread 2 up to time 2,
> + // but because of the broken clock it is now synchronized only up to time 1
> + //
> + // The global_acquire_ value helps to prevent this scenario.
> + // Namely, thread 3 will not trust any own clock values up to global_acquire_
> + // for the purposes of the last_acquire_ optimization.
> + atomic_uint64_t global_acquire_;
> +
> // Cached SyncClock (without dirty entries and release_store_tid_).
> // We reuse it for subsequent store-release operations without intervening
> // acquire operations. Since it is shared (and thus constant), clock value
> @@ -164,6 +213,7 @@ class ThreadClock {
> u64 clk_[kMaxTidInClock]; // Fixed size vector clock.
>
> bool IsAlreadyAcquired(const SyncClock *src) const;
> + bool HasAcquiredAfterRelease(const SyncClock *dst) const;
> void UpdateCurrentThread(ClockCache *c, SyncClock *dst) const;
> };
>
> @@ -185,6 +235,14 @@ ALWAYS_INLINE uptr ThreadClock::size() const {
> return nclk_;
> }
>
> +ALWAYS_INLINE void ThreadClock::NoteGlobalAcquire(u64 v) {
> + // Here we rely on the fact that AcquireGlobal is protected by
> + // ThreadRegistryLock, thus only one thread at a time executes it
> + // and values passed to this function should not go backwards.
> + CHECK_LE(atomic_load_relaxed(&global_acquire_), v);
> + atomic_store_relaxed(&global_acquire_, v);
> +}
> +
> ALWAYS_INLINE SyncClock::Iter SyncClock::begin() {
> return Iter(this);
> }
> diff --git a/libsanitizer/tsan/tsan_interceptors_posix.cpp b/libsanitizer/tsan/tsan_interceptors_posix.cpp
> index 8aea1e4ec05..718957c3703 100644
> --- a/libsanitizer/tsan/tsan_interceptors_posix.cpp
> +++ b/libsanitizer/tsan/tsan_interceptors_posix.cpp
> @@ -891,13 +891,16 @@ void DestroyThreadState() {
> ThreadFinish(thr);
> ProcUnwire(proc, thr);
> ProcDestroy(proc);
> + DTLS_Destroy();
> + cur_thread_finalize();
> +}
> +
> +void PlatformCleanUpThreadState(ThreadState *thr) {
> ThreadSignalContext *sctx = thr->signal_ctx;
> if (sctx) {
> thr->signal_ctx = 0;
> UnmapOrDie(sctx, sizeof(*sctx));
> }
> - DTLS_Destroy();
> - cur_thread_finalize();
> }
> } // namespace __tsan
>
> @@ -1016,7 +1019,7 @@ TSAN_INTERCEPTOR(int, pthread_create,
>
> TSAN_INTERCEPTOR(int, pthread_join, void *th, void **ret) {
> SCOPED_INTERCEPTOR_RAW(pthread_join, th, ret);
> - int tid = ThreadTid(thr, pc, (uptr)th);
> + int tid = ThreadConsumeTid(thr, pc, (uptr)th);
> ThreadIgnoreBegin(thr, pc);
> int res = BLOCK_REAL(pthread_join)(th, ret);
> ThreadIgnoreEnd(thr, pc);
> @@ -1029,8 +1032,8 @@ TSAN_INTERCEPTOR(int, pthread_join, void *th, void **ret) {
> DEFINE_REAL_PTHREAD_FUNCTIONS
>
> TSAN_INTERCEPTOR(int, pthread_detach, void *th) {
> - SCOPED_TSAN_INTERCEPTOR(pthread_detach, th);
> - int tid = ThreadTid(thr, pc, (uptr)th);
> + SCOPED_INTERCEPTOR_RAW(pthread_detach, th);
> + int tid = ThreadConsumeTid(thr, pc, (uptr)th);
> int res = REAL(pthread_detach)(th);
> if (res == 0) {
> ThreadDetach(thr, pc, tid);
> @@ -1050,8 +1053,8 @@ TSAN_INTERCEPTOR(void, pthread_exit, void *retval) {
>
> #if SANITIZER_LINUX
> TSAN_INTERCEPTOR(int, pthread_tryjoin_np, void *th, void **ret) {
> - SCOPED_TSAN_INTERCEPTOR(pthread_tryjoin_np, th, ret);
> - int tid = ThreadTid(thr, pc, (uptr)th);
> + SCOPED_INTERCEPTOR_RAW(pthread_tryjoin_np, th, ret);
> + int tid = ThreadConsumeTid(thr, pc, (uptr)th);
> ThreadIgnoreBegin(thr, pc);
> int res = REAL(pthread_tryjoin_np)(th, ret);
> ThreadIgnoreEnd(thr, pc);
> @@ -1064,8 +1067,8 @@ TSAN_INTERCEPTOR(int, pthread_tryjoin_np, void *th, void **ret) {
>
> TSAN_INTERCEPTOR(int, pthread_timedjoin_np, void *th, void **ret,
> const struct timespec *abstime) {
> - SCOPED_TSAN_INTERCEPTOR(pthread_timedjoin_np, th, ret, abstime);
> - int tid = ThreadTid(thr, pc, (uptr)th);
> + SCOPED_INTERCEPTOR_RAW(pthread_timedjoin_np, th, ret, abstime);
> + int tid = ThreadConsumeTid(thr, pc, (uptr)th);
> ThreadIgnoreBegin(thr, pc);
> int res = BLOCK_REAL(pthread_timedjoin_np)(th, ret, abstime);
> ThreadIgnoreEnd(thr, pc);
> diff --git a/libsanitizer/tsan/tsan_platform.h b/libsanitizer/tsan/tsan_platform.h
> index 63eb14fcd34..7256d64e507 100644
> --- a/libsanitizer/tsan/tsan_platform.h
> +++ b/libsanitizer/tsan/tsan_platform.h
> @@ -1021,6 +1021,7 @@ int call_pthread_cancel_with_cleanup(int(*fn)(void *c, void *m,
> void(*cleanup)(void *arg), void *arg);
>
> void DestroyThreadState();
> +void PlatformCleanUpThreadState(ThreadState *thr);
>
> } // namespace __tsan
>
> diff --git a/libsanitizer/tsan/tsan_platform_mac.cpp b/libsanitizer/tsan/tsan_platform_mac.cpp
> index 326ca8532e5..f92ecc5e40f 100644
> --- a/libsanitizer/tsan/tsan_platform_mac.cpp
> +++ b/libsanitizer/tsan/tsan_platform_mac.cpp
> @@ -19,6 +19,7 @@
> #include "sanitizer_common/sanitizer_libc.h"
> #include "sanitizer_common/sanitizer_posix.h"
> #include "sanitizer_common/sanitizer_procmaps.h"
> +#include "sanitizer_common/sanitizer_ptrauth.h"
> #include "sanitizer_common/sanitizer_stackdepot.h"
> #include "tsan_platform.h"
> #include "tsan_rtl.h"
> @@ -75,9 +76,14 @@ static uptr main_thread_identity = 0;
> ALIGNED(64) static char main_thread_state[sizeof(ThreadState)];
> static ThreadState *main_thread_state_loc = (ThreadState *)main_thread_state;
>
> +// We cannot use pthread_self() before libpthread has been initialized. Our
> +// current heuristic for guarding this is checking `main_thread_identity` which
> +// is only assigned in `__tsan::InitializePlatform`.
> static ThreadState **cur_thread_location() {
> + if (main_thread_identity == 0)
> + return &main_thread_state_loc;
> uptr thread_identity = (uptr)pthread_self();
> - if (thread_identity == main_thread_identity || main_thread_identity == 0)
> + if (thread_identity == main_thread_identity)
> return &main_thread_state_loc;
> return (ThreadState **)MemToShadow(thread_identity);
> }
> @@ -269,6 +275,8 @@ void InitializePlatform() {
> uptr ExtractLongJmpSp(uptr *env) {
> uptr mangled_sp = env[LONG_JMP_SP_ENV_SLOT];
> uptr sp = mangled_sp ^ longjmp_xor_key;
> + sp = (uptr)ptrauth_auth_data((void *)sp, ptrauth_key_asdb,
> + ptrauth_string_discriminator("sp"));
> return sp;
> }
>
> diff --git a/libsanitizer/tsan/tsan_rtl.cpp b/libsanitizer/tsan/tsan_rtl.cpp
> index 3f3c0cce119..13c9b770f50 100644
> --- a/libsanitizer/tsan/tsan_rtl.cpp
> +++ b/libsanitizer/tsan/tsan_rtl.cpp
> @@ -144,7 +144,7 @@ static void MemoryProfiler(Context *ctx, fd_t fd, int i) {
> WriteToFile(fd, buf.data(), internal_strlen(buf.data()));
> }
>
> -static void BackgroundThread(void *arg) {
> +static void *BackgroundThread(void *arg) {
> // This is a non-initialized non-user thread, nothing to see here.
> // We don't use ScopedIgnoreInterceptors, because we want ignores to be
> // enabled even when the thread function exits (e.g. during pthread thread
> @@ -220,6 +220,7 @@ static void BackgroundThread(void *arg) {
> }
> }
> }
> + return nullptr;
> }
>
> static void StartBackgroundThread() {
> @@ -494,14 +495,23 @@ int Finalize(ThreadState *thr) {
> void ForkBefore(ThreadState *thr, uptr pc) {
> ctx->thread_registry->Lock();
> ctx->report_mtx.Lock();
> + // Ignore memory accesses in the pthread_atfork callbacks.
> + // If any of them triggers a data race we will deadlock
> + // on the report_mtx.
> + // We could ignore interceptors and sync operations as well,
> + // but so far it's unclear if it will do more good or harm.
> + // Unnecessarily ignoring things can lead to false positives later.
> + ThreadIgnoreBegin(thr, pc);
> }
>
> void ForkParentAfter(ThreadState *thr, uptr pc) {
> + ThreadIgnoreEnd(thr, pc); // Begin is in ForkBefore.
> ctx->report_mtx.Unlock();
> ctx->thread_registry->Unlock();
> }
>
> void ForkChildAfter(ThreadState *thr, uptr pc) {
> + ThreadIgnoreEnd(thr, pc); // Begin is in ForkBefore.
> ctx->report_mtx.Unlock();
> ctx->thread_registry->Unlock();
>
> diff --git a/libsanitizer/tsan/tsan_rtl.h b/libsanitizer/tsan/tsan_rtl.h
> index c38fc43a9f8..d3bb61ff87d 100644
> --- a/libsanitizer/tsan/tsan_rtl.h
> +++ b/libsanitizer/tsan/tsan_rtl.h
> @@ -775,7 +775,7 @@ int ThreadCreate(ThreadState *thr, uptr pc, uptr uid, bool detached);
> void ThreadStart(ThreadState *thr, int tid, tid_t os_id,
> ThreadType thread_type);
> void ThreadFinish(ThreadState *thr);
> -int ThreadTid(ThreadState *thr, uptr pc, uptr uid);
> +int ThreadConsumeTid(ThreadState *thr, uptr pc, uptr uid);
> void ThreadJoin(ThreadState *thr, uptr pc, int tid);
> void ThreadDetach(ThreadState *thr, uptr pc, int tid);
> void ThreadFinalize(ThreadState *thr);
> @@ -813,10 +813,12 @@ void Acquire(ThreadState *thr, uptr pc, uptr addr);
> // approximation of the actual required synchronization.
> void AcquireGlobal(ThreadState *thr, uptr pc);
> void Release(ThreadState *thr, uptr pc, uptr addr);
> +void ReleaseStoreAcquire(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 ReleaseStoreAcquireImpl(ThreadState *thr, uptr pc, SyncClock *c);
> void ReleaseStoreImpl(ThreadState *thr, uptr pc, SyncClock *c);
> void AcquireReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c);
>
> diff --git a/libsanitizer/tsan/tsan_rtl_mutex.cpp b/libsanitizer/tsan/tsan_rtl_mutex.cpp
> index ce6e7cb2c4e..ebd0d722181 100644
> --- a/libsanitizer/tsan/tsan_rtl_mutex.cpp
> +++ b/libsanitizer/tsan/tsan_rtl_mutex.cpp
> @@ -415,8 +415,10 @@ static void UpdateClockCallback(ThreadContextBase *tctx_base, void *arg) {
> ThreadState *thr = reinterpret_cast<ThreadState*>(arg);
> ThreadContext *tctx = static_cast<ThreadContext*>(tctx_base);
> u64 epoch = tctx->epoch1;
> - if (tctx->status == ThreadStatusRunning)
> + if (tctx->status == ThreadStatusRunning) {
> epoch = tctx->thr->fast_state.epoch();
> + tctx->thr->clock.NoteGlobalAcquire(epoch);
> + }
> thr->clock.set(&thr->proc()->clock_cache, tctx->tid, epoch);
> }
>
> @@ -429,6 +431,18 @@ void AcquireGlobal(ThreadState *thr, uptr pc) {
> UpdateClockCallback, thr);
> }
>
> +void ReleaseStoreAcquire(ThreadState *thr, uptr pc, uptr addr) {
> + DPrintf("#%d: ReleaseStoreAcquire %zx\n", thr->tid, addr);
> + if (thr->ignore_sync)
> + return;
> + SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true);
> + thr->fast_state.IncrementEpoch();
> + // Can't increment epoch w/o writing to the trace as well.
> + TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0);
> + ReleaseStoreAcquireImpl(thr, pc, &s->clock);
> + s->mtx.Unlock();
> +}
> +
> void Release(ThreadState *thr, uptr pc, uptr addr) {
> DPrintf("#%d: Release %zx\n", thr->tid, addr);
> if (thr->ignore_sync)
> @@ -482,6 +496,15 @@ void AcquireImpl(ThreadState *thr, uptr pc, SyncClock *c) {
> StatInc(thr, StatSyncAcquire);
> }
>
> +void ReleaseStoreAcquireImpl(ThreadState *thr, uptr pc, SyncClock *c) {
> + if (thr->ignore_sync)
> + return;
> + thr->clock.set(thr->fast_state.epoch());
> + thr->fast_synch_epoch = thr->fast_state.epoch();
> + thr->clock.releaseStoreAcquire(&thr->proc()->clock_cache, c);
> + StatInc(thr, StatSyncReleaseStoreAcquire);
> +}
> +
> void ReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c) {
> if (thr->ignore_sync)
> return;
> diff --git a/libsanitizer/tsan/tsan_rtl_ppc64.S b/libsanitizer/tsan/tsan_rtl_ppc64.S
> index 9e533a71a9c..8285e21aa1e 100644
> --- a/libsanitizer/tsan/tsan_rtl_ppc64.S
> +++ b/libsanitizer/tsan/tsan_rtl_ppc64.S
> @@ -1,6 +1,5 @@
> #include "tsan_ppc_regs.h"
>
> - .machine altivec
> .section .text
> .hidden __tsan_setjmp
> .globl _setjmp
> diff --git a/libsanitizer/tsan/tsan_rtl_thread.cpp b/libsanitizer/tsan/tsan_rtl_thread.cpp
> index 0ac1ee99c47..d80146735ea 100644
> --- a/libsanitizer/tsan/tsan_rtl_thread.cpp
> +++ b/libsanitizer/tsan/tsan_rtl_thread.cpp
> @@ -144,6 +144,9 @@ void ThreadContext::OnFinished() {
> thr->clock.ResetCached(&thr->proc()->clock_cache);
> #if !SANITIZER_GO
> thr->last_sleep_clock.ResetCached(&thr->proc()->clock_cache);
> +#endif
> +#if !SANITIZER_GO
> + PlatformCleanUpThreadState(thr);
> #endif
> thr->~ThreadState();
> #if TSAN_COLLECT_STATS
> @@ -285,19 +288,34 @@ void ThreadFinish(ThreadState *thr) {
> ctx->thread_registry->FinishThread(thr->tid);
> }
>
> -static bool FindThreadByUid(ThreadContextBase *tctx, void *arg) {
> - uptr uid = (uptr)arg;
> - if (tctx->user_id == uid && tctx->status != ThreadStatusInvalid) {
> +struct ConsumeThreadContext {
> + uptr uid;
> + ThreadContextBase *tctx;
> +};
> +
> +static bool ConsumeThreadByUid(ThreadContextBase *tctx, void *arg) {
> + ConsumeThreadContext *findCtx = (ConsumeThreadContext *)arg;
> + if (tctx->user_id == findCtx->uid && tctx->status != ThreadStatusInvalid) {
> + if (findCtx->tctx) {
> + // Ensure that user_id is unique. If it's not the case we are screwed.
> + // Something went wrong before, but now there is no way to recover.
> + // Returning a wrong thread is not an option, it may lead to very hard
> + // to debug false positives (e.g. if we join a wrong thread).
> + Report("ThreadSanitizer: dup thread with used id 0x%zx\n", findCtx->uid);
> + Die();
> + }
> + findCtx->tctx = tctx;
> tctx->user_id = 0;
> - return true;
> }
> return false;
> }
>
> -int ThreadTid(ThreadState *thr, uptr pc, uptr uid) {
> - int res = ctx->thread_registry->FindThread(FindThreadByUid, (void*)uid);
> - DPrintf("#%d: ThreadTid uid=%zu tid=%d\n", thr->tid, uid, res);
> - return res;
> +int ThreadConsumeTid(ThreadState *thr, uptr pc, uptr uid) {
> + ConsumeThreadContext findCtx = {uid, nullptr};
> + ctx->thread_registry->FindThread(ConsumeThreadByUid, &findCtx);
> + int tid = findCtx.tctx ? findCtx.tctx->tid : ThreadRegistry::kUnknownTid;
> + DPrintf("#%d: ThreadTid uid=%zu tid=%d\n", thr->tid, uid, tid);
> + return tid;
> }
>
> void ThreadJoin(ThreadState *thr, uptr pc, int tid) {
> diff --git a/libsanitizer/tsan/tsan_stat.h b/libsanitizer/tsan/tsan_stat.h
> index 94e18bc66df..8b26a59bb2e 100644
> --- a/libsanitizer/tsan/tsan_stat.h
> +++ b/libsanitizer/tsan/tsan_stat.h
> @@ -68,6 +68,7 @@ enum StatType {
> StatSyncDestroyed,
> StatSyncAcquire,
> StatSyncRelease,
> + StatSyncReleaseStoreAcquire,
>
> // Clocks - acquire.
> StatClockAcquire,
> diff --git a/libsanitizer/ubsan/ubsan_checks.inc b/libsanitizer/ubsan/ubsan_checks.inc
> index 33a8dfcde02..2c1529a7d92 100644
> --- a/libsanitizer/ubsan/ubsan_checks.inc
> +++ b/libsanitizer/ubsan/ubsan_checks.inc
> @@ -18,6 +18,8 @@
>
> UBSAN_CHECK(GenericUB, "undefined-behavior", "undefined")
> UBSAN_CHECK(NullPointerUse, "null-pointer-use", "null")
> +UBSAN_CHECK(NullPointerUseWithNullability, "null-pointer-use",
> + "nullability-assign")
> UBSAN_CHECK(NullptrWithOffset, "nullptr-with-offset", "pointer-overflow")
> UBSAN_CHECK(NullptrWithNonZeroOffset, "nullptr-with-nonzero-offset",
> "pointer-overflow")
> @@ -59,6 +61,10 @@ UBSAN_CHECK(InvalidEnumLoad, "invalid-enum-load", "enum")
> UBSAN_CHECK(FunctionTypeMismatch, "function-type-mismatch", "function")
> UBSAN_CHECK(InvalidNullReturn, "invalid-null-return",
> "returns-nonnull-attribute")
> +UBSAN_CHECK(InvalidNullReturnWithNullability, "invalid-null-return",
> + "nullability-return")
> UBSAN_CHECK(InvalidNullArgument, "invalid-null-argument", "nonnull-attribute")
> +UBSAN_CHECK(InvalidNullArgumentWithNullability, "invalid-null-argument",
> + "nullability-arg")
> UBSAN_CHECK(DynamicTypeMismatch, "dynamic-type-mismatch", "vptr")
> UBSAN_CHECK(CFIBadType, "cfi-bad-type", "cfi")
> diff --git a/libsanitizer/ubsan/ubsan_flags.cpp b/libsanitizer/ubsan/ubsan_flags.cpp
> index 80de2a6d101..721c2273f13 100644
> --- a/libsanitizer/ubsan/ubsan_flags.cpp
> +++ b/libsanitizer/ubsan/ubsan_flags.cpp
> @@ -54,7 +54,6 @@ void InitializeFlags() {
> {
> CommonFlags cf;
> cf.CopyFrom(*common_flags());
> - cf.print_summary = false;
> cf.external_symbolizer_path = GetFlag("UBSAN_SYMBOLIZER_PATH");
> OverrideCommonFlags(cf);
> }
> diff --git a/libsanitizer/ubsan/ubsan_handlers.cpp b/libsanitizer/ubsan/ubsan_handlers.cpp
> index 0ddbb50c26c..7f6a46fb6cf 100644
> --- a/libsanitizer/ubsan/ubsan_handlers.cpp
> +++ b/libsanitizer/ubsan/ubsan_handlers.cpp
> @@ -36,6 +36,45 @@ bool ignoreReport(SourceLocation SLoc, ReportOptions Opts, ErrorType ET) {
> return SLoc.isDisabled() || IsPCSuppressed(ET, Opts.pc, SLoc.getFilename());
> }
>
> +/// Situations in which we might emit a check for the suitability of a
> +/// pointer or glvalue. Needs to be kept in sync with CodeGenFunction.h in
> +/// clang.
> +enum TypeCheckKind {
> + /// Checking the operand of a load. Must be suitably sized and aligned.
> + TCK_Load,
> + /// Checking the destination of a store. Must be suitably sized and aligned.
> + TCK_Store,
> + /// Checking the bound value in a reference binding. Must be suitably sized
> + /// and aligned, but is not required to refer to an object (until the
> + /// reference is used), per core issue 453.
> + TCK_ReferenceBinding,
> + /// Checking the object expression in a non-static data member access. Must
> + /// be an object within its lifetime.
> + TCK_MemberAccess,
> + /// Checking the 'this' pointer for a call to a non-static member function.
> + /// Must be an object within its lifetime.
> + TCK_MemberCall,
> + /// Checking the 'this' pointer for a constructor call.
> + TCK_ConstructorCall,
> + /// Checking the operand of a static_cast to a derived pointer type. Must be
> + /// null or an object within its lifetime.
> + TCK_DowncastPointer,
> + /// Checking the operand of a static_cast to a derived reference type. Must
> + /// be an object within its lifetime.
> + TCK_DowncastReference,
> + /// Checking the operand of a cast to a base object. Must be suitably sized
> + /// and aligned.
> + TCK_Upcast,
> + /// Checking the operand of a cast to a virtual base object. Must be an
> + /// object within its lifetime.
> + TCK_UpcastToVirtualBase,
> + /// Checking the value assigned to a _Nonnull pointer. Must not be null.
> + TCK_NonnullAssign,
> + /// Checking the operand of a dynamic_cast or a typeid expression. Must be
> + /// null or an object within its lifetime.
> + TCK_DynamicOperation
> +};
> +
> const char *TypeCheckKinds[] = {
> "load of", "store to", "reference binding to", "member access within",
> "member call on", "constructor call on", "downcast of", "downcast of",
> @@ -50,7 +89,9 @@ static void handleTypeMismatchImpl(TypeMismatchData *Data, ValueHandle Pointer,
> uptr Alignment = (uptr)1 << Data->LogAlignment;
> ErrorType ET;
> if (!Pointer)
> - ET = ErrorType::NullPointerUse;
> + ET = (Data->TypeCheckKind == TCK_NonnullAssign)
> + ? ErrorType::NullPointerUseWithNullability
> + : ErrorType::NullPointerUse;
> else if (Pointer & (Alignment - 1))
> ET = ErrorType::MisalignedPointerUse;
> else
> @@ -71,6 +112,7 @@ static void handleTypeMismatchImpl(TypeMismatchData *Data, ValueHandle Pointer,
>
> switch (ET) {
> case ErrorType::NullPointerUse:
> + case ErrorType::NullPointerUseWithNullability:
> Diag(Loc, DL_Error, ET, "%0 null pointer of type %1")
> << TypeCheckKinds[Data->TypeCheckKind] << Data->Type;
> break;
> @@ -604,7 +646,8 @@ static void handleNonNullReturn(NonNullReturnData *Data, SourceLocation *LocPtr,
> UNREACHABLE("source location pointer is null!");
>
> SourceLocation Loc = LocPtr->acquire();
> - ErrorType ET = ErrorType::InvalidNullReturn;
> + ErrorType ET = IsAttr ? ErrorType::InvalidNullReturn
> + : ErrorType::InvalidNullReturnWithNullability;
>
> if (ignoreReport(Loc, Opts, ET))
> return;
> @@ -648,7 +691,8 @@ void __ubsan::__ubsan_handle_nullability_return_v1_abort(
> static void handleNonNullArg(NonNullArgData *Data, ReportOptions Opts,
> bool IsAttr) {
> SourceLocation Loc = Data->Loc.acquire();
> - ErrorType ET = ErrorType::InvalidNullArgument;
> + ErrorType ET = IsAttr ? ErrorType::InvalidNullArgument
> + : ErrorType::InvalidNullArgumentWithNullability;
>
> if (ignoreReport(Loc, Opts, ET))
> return;
> @@ -819,21 +863,6 @@ void __ubsan_handle_cfi_bad_type(CFICheckFailData *Data, ValueHandle Vtable,
>
> } // namespace __ubsan
>
> -void __ubsan::__ubsan_handle_cfi_bad_icall(CFIBadIcallData *CallData,
> - ValueHandle Function) {
> - GET_REPORT_OPTIONS(false);
> - CFICheckFailData Data = {CFITCK_ICall, CallData->Loc, CallData->Type};
> - handleCFIBadIcall(&Data, Function, Opts);
> -}
> -
> -void __ubsan::__ubsan_handle_cfi_bad_icall_abort(CFIBadIcallData *CallData,
> - ValueHandle Function) {
> - GET_REPORT_OPTIONS(true);
> - CFICheckFailData Data = {CFITCK_ICall, CallData->Loc, CallData->Type};
> - handleCFIBadIcall(&Data, Function, Opts);
> - Die();
> -}
> -
> void __ubsan::__ubsan_handle_cfi_check_fail(CFICheckFailData *Data,
> ValueHandle Value,
> uptr ValidVtable) {
> diff --git a/libsanitizer/ubsan/ubsan_handlers.h b/libsanitizer/ubsan/ubsan_handlers.h
> index eba1cf918fc..22ca9642238 100644
> --- a/libsanitizer/ubsan/ubsan_handlers.h
> +++ b/libsanitizer/ubsan/ubsan_handlers.h
> @@ -207,20 +207,12 @@ enum CFITypeCheckKind : unsigned char {
> CFITCK_VMFCall,
> };
>
> -struct CFIBadIcallData {
> - SourceLocation Loc;
> - const TypeDescriptor &Type;
> -};
> -
> struct CFICheckFailData {
> CFITypeCheckKind CheckKind;
> SourceLocation Loc;
> const TypeDescriptor &Type;
> };
>
> -/// \brief Handle control flow integrity failure for indirect function calls.
> -RECOVERABLE(cfi_bad_icall, CFIBadIcallData *Data, ValueHandle Function)
> -
> /// \brief Handle control flow integrity failures.
> RECOVERABLE(cfi_check_fail, CFICheckFailData *Data, ValueHandle Function,
> uptr VtableIsValid)
> diff --git a/libsanitizer/ubsan/ubsan_init.cpp b/libsanitizer/ubsan/ubsan_init.cpp
> index 1a3b7d37267..e0be5a72ec4 100644
> --- a/libsanitizer/ubsan/ubsan_init.cpp
> +++ b/libsanitizer/ubsan/ubsan_init.cpp
> @@ -37,10 +37,12 @@ static void CommonStandaloneInit() {
> SanitizerToolName = GetSanititizerToolName();
> CacheBinaryName();
> InitializeFlags();
> + __sanitizer::InitializePlatformEarly();
> __sanitizer_set_report_path(common_flags()->log_path);
> AndroidLogInit();
> InitializeCoverage(common_flags()->coverage, common_flags()->coverage_dir);
> CommonInit();
> + Symbolizer::LateInitialize();
> }
>
> void __ubsan::InitAsStandalone() {
> diff --git a/libsanitizer/ubsan/ubsan_platform.h b/libsanitizer/ubsan/ubsan_platform.h
> index 58aabbe67b5..71d7fb18c9b 100644
> --- a/libsanitizer/ubsan/ubsan_platform.h
> +++ b/libsanitizer/ubsan/ubsan_platform.h
> @@ -12,7 +12,6 @@
> #ifndef UBSAN_PLATFORM_H
> #define UBSAN_PLATFORM_H
>
> -#ifndef CAN_SANITIZE_UB
> // Other platforms should be easy to add, and probably work as-is.
> #if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || \
> defined(__NetBSD__) || defined(__OpenBSD__) || \
> @@ -22,6 +21,5 @@
> #else
> # define CAN_SANITIZE_UB 0
> #endif
> -#endif //CAN_SANITIZE_UB
>
> #endif
> diff --git a/libsanitizer/ubsan/ubsan_type_hash_itanium.cpp b/libsanitizer/ubsan/ubsan_type_hash_itanium.cpp
> index 97846d4dd43..4f1708ba190 100644
> --- a/libsanitizer/ubsan/ubsan_type_hash_itanium.cpp
> +++ b/libsanitizer/ubsan/ubsan_type_hash_itanium.cpp
> @@ -16,6 +16,7 @@
> #include "ubsan_type_hash.h"
>
> #include "sanitizer_common/sanitizer_common.h"
> +#include "sanitizer_common/sanitizer_ptrauth.h"
>
> // The following are intended to be binary compatible with the definitions
> // given in the Itanium ABI. We make no attempt to be ODR-compatible with
> @@ -194,6 +195,7 @@ struct VtablePrefix {
> std::type_info *TypeInfo;
> };
> VtablePrefix *getVtablePrefix(void *Vtable) {
> + Vtable = ptrauth_auth_data(Vtable, ptrauth_key_cxx_vtable_pointer, 0);
> VtablePrefix *Vptr = reinterpret_cast<VtablePrefix*>(Vtable);
> VtablePrefix *Prefix = Vptr - 1;
> if (!IsAccessibleMemoryRange((uptr)Prefix, sizeof(VtablePrefix)))
[-- Attachment #2: 0002-Reapply-all-revisions-mentioned-in-LOCAL_PATCHES.patch --]
[-- Type: text/x-patch, Size: 12538 bytes --]
From 1fe7c3515fb311026e7fdc20a89744eedcfc3faf Mon Sep 17 00:00:00 2001
From: Martin Liska <mliska@suse.cz>
Date: Thu, 7 Nov 2019 10:34:14 +0100
Subject: [PATCH 2/2] Reapply all revisions mentioned in LOCAL_PATCHES.
(cherry picked from commit 21bb1625bd4f183984223ce31bd03ba47ed62f27)
---
libsanitizer/asan/asan_globals.cpp | 19 -------------------
libsanitizer/asan/asan_interceptors.h | 7 ++++++-
libsanitizer/asan/asan_mapping.h | 2 +-
.../sanitizer_linux_libcdep.cpp | 4 ++++
.../sanitizer_common/sanitizer_mac.cpp | 2 +-
.../sanitizer_platform_limits_linux.cpp | 7 +++++--
.../sanitizer_platform_limits_posix.h | 2 +-
.../sanitizer_common/sanitizer_stacktrace.cpp | 17 ++++++++++++-----
libsanitizer/tsan/tsan_rtl_ppc64.S | 1 +
libsanitizer/ubsan/ubsan_flags.cpp | 1 +
libsanitizer/ubsan/ubsan_handlers.cpp | 15 +++++++++++++++
libsanitizer/ubsan/ubsan_handlers.h | 8 ++++++++
libsanitizer/ubsan/ubsan_platform.h | 2 ++
13 files changed, 57 insertions(+), 30 deletions(-)
diff --git a/libsanitizer/asan/asan_globals.cpp b/libsanitizer/asan/asan_globals.cpp
index 9d7dbc6f264..e045c31cd1c 100644
--- a/libsanitizer/asan/asan_globals.cpp
+++ b/libsanitizer/asan/asan_globals.cpp
@@ -154,23 +154,6 @@ static void CheckODRViolationViaIndicator(const Global *g) {
}
}
-// Check ODR violation for given global G by checking if it's already poisoned.
-// We use this method in case compiler doesn't use private aliases for global
-// variables.
-static void CheckODRViolationViaPoisoning(const Global *g) {
- if (__asan_region_is_poisoned(g->beg, g->size_with_redzone)) {
- // This check may not be enough: if the first global is much larger
- // the entire redzone of the second global may be within the first global.
- for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) {
- if (g->beg == l->g->beg &&
- (flags()->detect_odr_violation >= 2 || g->size != l->g->size) &&
- !IsODRViolationSuppressed(g->name))
- ReportODRViolation(g, FindRegistrationSite(g),
- l->g, FindRegistrationSite(l->g));
- }
- }
-}
-
// Clang provides two different ways for global variables protection:
// it can poison the global itself or its private alias. In former
// case we may poison same symbol multiple times, that can help us to
@@ -216,8 +199,6 @@ static void RegisterGlobal(const Global *g) {
// where two globals with the same name are defined in different modules.
if (UseODRIndicator(g))
CheckODRViolationViaIndicator(g);
- else
- CheckODRViolationViaPoisoning(g);
}
if (CanPoisonMemory())
PoisonRedZones(*g);
diff --git a/libsanitizer/asan/asan_interceptors.h b/libsanitizer/asan/asan_interceptors.h
index 8e9525673d1..43cb4e3bb4f 100644
--- a/libsanitizer/asan/asan_interceptors.h
+++ b/libsanitizer/asan/asan_interceptors.h
@@ -81,7 +81,12 @@ void InitializePlatformInterceptors();
#if ASAN_HAS_EXCEPTIONS && !SANITIZER_WINDOWS && !SANITIZER_SOLARIS && \
!SANITIZER_NETBSD
# define ASAN_INTERCEPT___CXA_THROW 1
-# define ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION 1
+# if ! defined(ASAN_HAS_CXA_RETHROW_PRIMARY_EXCEPTION) \
+ || ASAN_HAS_CXA_RETHROW_PRIMARY_EXCEPTION
+# define ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION 1
+# else
+# define ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION 0
+# endif
# if defined(_GLIBCXX_SJLJ_EXCEPTIONS) || (SANITIZER_IOS && defined(__arm__))
# define ASAN_INTERCEPT__UNWIND_SJLJ_RAISEEXCEPTION 1
# else
diff --git a/libsanitizer/asan/asan_mapping.h b/libsanitizer/asan/asan_mapping.h
index f239c3ee2ff..a7136de60d2 100644
--- a/libsanitizer/asan/asan_mapping.h
+++ b/libsanitizer/asan/asan_mapping.h
@@ -178,7 +178,7 @@ static const u64 kAArch64_ShadowOffset64 = 1ULL << 36;
static const u64 kRiscv64_ShadowOffset64 = 0x20000000;
static const u64 kMIPS32_ShadowOffset32 = 0x0aaa0000;
static const u64 kMIPS64_ShadowOffset64 = 1ULL << 37;
-static const u64 kPPC64_ShadowOffset64 = 1ULL << 44;
+static const u64 kPPC64_ShadowOffset64 = 1ULL << 41;
static const u64 kSystemZ_ShadowOffset64 = 1ULL << 52;
static const u64 kSPARC64_ShadowOffset64 = 1ULL << 43; // 0x80000000000
static const u64 kFreeBSD_ShadowOffset32 = 1ULL << 30; // 0x40000000
diff --git a/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp
index b8b999363ff..af077439478 100644
--- a/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp
@@ -730,9 +730,13 @@ u32 GetNumberOfCPUs() {
#elif SANITIZER_SOLARIS
return sysconf(_SC_NPROCESSORS_ONLN);
#else
+#if defined(CPU_COUNT)
cpu_set_t CPUs;
CHECK_EQ(sched_getaffinity(0, sizeof(cpu_set_t), &CPUs), 0);
return CPU_COUNT(&CPUs);
+#else
+ return 1;
+#endif
#endif
}
diff --git a/libsanitizer/sanitizer_common/sanitizer_mac.cpp b/libsanitizer/sanitizer_common/sanitizer_mac.cpp
index b1271120c00..36a8f79cbdb 100644
--- a/libsanitizer/sanitizer_common/sanitizer_mac.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_mac.cpp
@@ -37,7 +37,7 @@
extern char **environ;
#endif
-#if defined(__has_include) && __has_include(<os/trace.h>)
+#if defined(__has_include) && __has_include(<os/trace.h>) && defined(__BLOCKS__)
#define SANITIZER_OS_TRACE 1
#include <os/trace.h>
#else
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cpp b/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cpp
index c51327e1269..f22f5039128 100644
--- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cpp
@@ -26,9 +26,12 @@
// 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.
+// fine with newer headers, too. Beware that with <sys/stat.h>, struct stat
+// takes the form of struct stat64 on 32-bit platforms if _FILE_OFFSET_BITS=64.
+// Also, for some platforms (e.g. mips) there are additional members in the
+// <sys/stat.h> struct stat:s.
#include <linux/posix_types.h>
-#if defined(__x86_64__) || defined(__mips__)
+#if defined(__x86_64__)
#include <sys/stat.h>
#else
#define ino_t __kernel_ino_t
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h
index e69560ee39e..0812039b038 100644
--- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h
+++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h
@@ -83,7 +83,7 @@ const unsigned struct_kernel_stat64_sz = 104;
#elif defined(__mips__)
const unsigned struct_kernel_stat_sz = SANITIZER_ANDROID
? FIRST_32_SECOND_64(104, 128)
- : FIRST_32_SECOND_64(160, 216);
+ : FIRST_32_SECOND_64(144, 216);
const unsigned struct_kernel_stat64_sz = 104;
#elif defined(__s390__) && !defined(__s390x__)
const unsigned struct_kernel_stat_sz = 64;
diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp b/libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp
index b0487d8987d..b28fc1cf736 100644
--- a/libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp
@@ -84,8 +84,8 @@ static inline uhwptr *GetCanonicFrame(uptr bp,
// Nope, this does not look right either. This means the frame after next does
// not have a valid frame pointer, but we can still extract the caller PC.
// Unfortunately, there is no way to decide between GCC and LLVM frame
- // layouts. Assume LLVM.
- return bp_prev;
+ // layouts. Assume GCC.
+ return bp_prev - 1;
#else
return (uhwptr*)bp;
#endif
@@ -108,14 +108,21 @@ void BufferedStackTrace::UnwindFast(uptr pc, uptr bp, uptr stack_top,
IsAligned((uptr)frame, sizeof(*frame)) &&
size < max_depth) {
#ifdef __powerpc__
- // PowerPC ABIs specify that the return address is saved at offset
- // 16 of the *caller's* stack frame. Thus we must dereference the
- // back chain to find the caller frame before extracting it.
+ // PowerPC ABIs specify that the return address is saved on the
+ // *caller's* stack frame. Thus we must dereference the back chain
+ // to find the caller frame before extracting it.
uhwptr *caller_frame = (uhwptr*)frame[0];
if (!IsValidFrame((uptr)caller_frame, stack_top, bottom) ||
!IsAligned((uptr)caller_frame, sizeof(uhwptr)))
break;
+ // For most ABIs the offset where the return address is saved is two
+ // register sizes. The exception is the SVR4 ABI, which uses an
+ // offset of only one register size.
+#ifdef _CALL_SYSV
+ uhwptr pc1 = caller_frame[1];
+#else
uhwptr pc1 = caller_frame[2];
+#endif
#elif defined(__s390__)
uhwptr pc1 = frame[14];
#elif defined(__riscv)
diff --git a/libsanitizer/tsan/tsan_rtl_ppc64.S b/libsanitizer/tsan/tsan_rtl_ppc64.S
index 8285e21aa1e..9e533a71a9c 100644
--- a/libsanitizer/tsan/tsan_rtl_ppc64.S
+++ b/libsanitizer/tsan/tsan_rtl_ppc64.S
@@ -1,5 +1,6 @@
#include "tsan_ppc_regs.h"
+ .machine altivec
.section .text
.hidden __tsan_setjmp
.globl _setjmp
diff --git a/libsanitizer/ubsan/ubsan_flags.cpp b/libsanitizer/ubsan/ubsan_flags.cpp
index 25cefd46ce2..9a66bd37518 100644
--- a/libsanitizer/ubsan/ubsan_flags.cpp
+++ b/libsanitizer/ubsan/ubsan_flags.cpp
@@ -50,6 +50,7 @@ void InitializeFlags() {
{
CommonFlags cf;
cf.CopyFrom(*common_flags());
+ cf.print_summary = false;
cf.external_symbolizer_path = GetFlag("UBSAN_SYMBOLIZER_PATH");
OverrideCommonFlags(cf);
}
diff --git a/libsanitizer/ubsan/ubsan_handlers.cpp b/libsanitizer/ubsan/ubsan_handlers.cpp
index e201e6bba22..2184625aa6e 100644
--- a/libsanitizer/ubsan/ubsan_handlers.cpp
+++ b/libsanitizer/ubsan/ubsan_handlers.cpp
@@ -894,6 +894,21 @@ void __ubsan_handle_cfi_bad_type(CFICheckFailData *Data, ValueHandle Vtable,
} // namespace __ubsan
+void __ubsan::__ubsan_handle_cfi_bad_icall(CFIBadIcallData *CallData,
+ ValueHandle Function) {
+ GET_REPORT_OPTIONS(false);
+ CFICheckFailData Data = {CFITCK_ICall, CallData->Loc, CallData->Type};
+ handleCFIBadIcall(&Data, Function, Opts);
+}
+
+void __ubsan::__ubsan_handle_cfi_bad_icall_abort(CFIBadIcallData *CallData,
+ ValueHandle Function) {
+ GET_REPORT_OPTIONS(true);
+ CFICheckFailData Data = {CFITCK_ICall, CallData->Loc, CallData->Type};
+ handleCFIBadIcall(&Data, Function, Opts);
+ Die();
+}
+
void __ubsan::__ubsan_handle_cfi_check_fail(CFICheckFailData *Data,
ValueHandle Value,
uptr ValidVtable) {
diff --git a/libsanitizer/ubsan/ubsan_handlers.h b/libsanitizer/ubsan/ubsan_handlers.h
index 219fb15de55..9f412353fc0 100644
--- a/libsanitizer/ubsan/ubsan_handlers.h
+++ b/libsanitizer/ubsan/ubsan_handlers.h
@@ -215,12 +215,20 @@ enum CFITypeCheckKind : unsigned char {
CFITCK_VMFCall,
};
+struct CFIBadIcallData {
+ SourceLocation Loc;
+ const TypeDescriptor &Type;
+};
+
struct CFICheckFailData {
CFITypeCheckKind CheckKind;
SourceLocation Loc;
const TypeDescriptor &Type;
};
+/// \brief Handle control flow integrity failure for indirect function calls.
+RECOVERABLE(cfi_bad_icall, CFIBadIcallData *Data, ValueHandle Function)
+
/// \brief Handle control flow integrity failures.
RECOVERABLE(cfi_check_fail, CFICheckFailData *Data, ValueHandle Function,
uptr VtableIsValid)
diff --git a/libsanitizer/ubsan/ubsan_platform.h b/libsanitizer/ubsan/ubsan_platform.h
index 71d7fb18c9b..58aabbe67b5 100644
--- a/libsanitizer/ubsan/ubsan_platform.h
+++ b/libsanitizer/ubsan/ubsan_platform.h
@@ -12,6 +12,7 @@
#ifndef UBSAN_PLATFORM_H
#define UBSAN_PLATFORM_H
+#ifndef CAN_SANITIZE_UB
// Other platforms should be easy to add, and probably work as-is.
#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || \
defined(__NetBSD__) || defined(__OpenBSD__) || \
@@ -21,5 +22,6 @@
#else
# define CAN_SANITIZE_UB 0
#endif
+#endif //CAN_SANITIZE_UB
#endif
--
2.28.0
[-- Attachment #3: 0001-libsanitizer-merge-from-master.patch.bz2 --]
[-- Type: application/x-bzip, Size: 62877 bytes --]
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH] Libsanitizer: merge from master.
2020-10-16 8:59 ` Martin Liška
@ 2020-10-19 7:04 ` Tobias Burnus
2020-10-19 7:11 ` Martin Liška
0 siblings, 1 reply; 17+ messages in thread
From: Tobias Burnus @ 2020-10-19 7:04 UTC (permalink / raw)
To: Martin Liška, gcc-patches
Hi Martin,
this patch caused here a build fail:
gcc-mainline/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp:490:39: error: 'NT_X86_XSTATE' was not declared in this scope
It turned out that the used GLIBC of the cross build is 2.11.1.
And that one does not contain this #define in 'elf.h'.
I wonder whether we should do something like the following – what do you think?
--- a/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp
@@ -490 +490,5 @@ typedef user_regs_struct regs_struct;
-static constexpr uptr kExtraRegs[] = {NT_X86_XSTATE, NT_FPREGSET};
+static constexpr uptr kExtraRegs[] = {
+#ifdef NT_X86_XSTATE
+ NT_X86_XSTATE,
+#endif
+ DNT_FPREGSET};
Tobias
On 10/16/20 10:59 AM, Martin Liška wrote:
> On 6/2/20 8:00 AM, Martin Liška wrote:
>> Merged from revision b638b63b99d66786cb37336292604a2ae3490cfd.
>
> Hello.
>
> I'm going to install one more merge from master.
>
>>
>> The patch successfully bootstraps on x86_64-linux-gnu and
>> ppc64le-linux-gnu. I also tested ppc64-linux-gnu that exposed:
>> https://reviews.llvm.org/D80864 (which is fixed on master).
>
> Again I tested the patch on x86_64-linux-gnu and ppc64le-linux-gnu.
>
>>
>> Abidiff looks happy and I made UBSAN and ASAN bootstrap on
>> x86_64-linux-gnu.
>
> It's fine also now.
>
>>
>> I'm planning to do merge from master twice a year, once now and
>> next time short before stage1 closes.
>>
>> I am going to install the patches as merge from master is obvious
>> and I haven't made anything special.
>>
>> libsanitizer/ChangeLog:
>>
>> * MERGE: Merge from master.
>> ---
>> libsanitizer/MERGE | 2 +-
>> libsanitizer/asan/asan_globals.cpp | 19 +
>> libsanitizer/asan/asan_interceptors.h | 7 +-
>> libsanitizer/asan/asan_mapping.h | 2 +-
>> libsanitizer/asan/asan_report.cpp | 3 +
>> libsanitizer/asan/asan_thread.cpp | 2 +
>> .../include/sanitizer/linux_syscall_hooks.h | 8 +-
>> .../include/sanitizer/netbsd_syscall_hooks.h | 2 +-
>> .../include/sanitizer/tsan_interface.h | 20 +-
>> libsanitizer/lsan/lsan.cpp | 17 +-
>> libsanitizer/lsan/lsan.h | 6 +
>> libsanitizer/lsan/lsan_allocator.h | 5 +-
>> libsanitizer/lsan/lsan_common.cpp | 51 +-
>> libsanitizer/lsan/lsan_common.h | 17 +-
>> libsanitizer/lsan/lsan_common_fuchsia.cpp | 166 +++++
>> libsanitizer/lsan/lsan_common_linux.cpp | 3 +-
>> libsanitizer/lsan/lsan_common_mac.cpp | 3 +-
>> libsanitizer/lsan/lsan_fuchsia.cpp | 123 ++++
>> libsanitizer/lsan/lsan_fuchsia.h | 35 +
>> libsanitizer/lsan/lsan_interceptors.cpp | 19 +-
>> libsanitizer/lsan/lsan_linux.cpp | 6 +-
>> libsanitizer/lsan/lsan_posix.cpp | 96 +++
>> libsanitizer/lsan/lsan_posix.h | 49 ++
>> libsanitizer/lsan/lsan_thread.cpp | 98 +--
>> libsanitizer/lsan/lsan_thread.h | 35 +-
>> .../sanitizer_common/sanitizer_allocator.cpp | 4 +-
>> .../sanitizer_allocator_primary64.h | 10 +-
>> .../sanitizer_common/sanitizer_common.cpp | 2 +
>> .../sanitizer_common/sanitizer_common.h | 5 +-
>> .../sanitizer_common_interceptors.inc | 190 +++++-
>> ...izer_common_interceptors_netbsd_compat.inc | 128 ++++
>> .../sanitizer_common_libcdep.cpp | 12 +-
>> .../sanitizer_common_syscalls.inc | 17 +
>> .../sanitizer_coverage_fuchsia.cpp | 25 +-
>> .../sanitizer_coverage_interface.inc | 1 +
>> .../sanitizer_coverage_libcdep_new.cpp | 1 +
>> .../sanitizer_common/sanitizer_file.h | 4 +-
>> .../sanitizer_flag_parser.cpp | 11 +-
>> .../sanitizer_common/sanitizer_flag_parser.h | 49 ++
>> .../sanitizer_common/sanitizer_flags.cpp | 10 +-
>> .../sanitizer_common/sanitizer_freebsd.h | 23 +-
>> .../sanitizer_common/sanitizer_fuchsia.cpp | 4 +
>> .../sanitizer_common/sanitizer_fuchsia.h | 6 +
>> .../sanitizer_interceptors_ioctl_netbsd.inc | 18 +-
>> .../sanitizer_interface_internal.h | 6 +-
>> .../sanitizer_internal_defs.h | 2 +-
>> .../sanitizer_common/sanitizer_libc.h | 2 +
>> .../sanitizer_common/sanitizer_linux.cpp | 151 ++++-
>> .../sanitizer_common/sanitizer_linux.h | 2 +
>> .../sanitizer_linux_libcdep.cpp | 17 +-
>> .../sanitizer_common/sanitizer_linux_s390.cpp | 11 +-
>> .../sanitizer_common/sanitizer_mac.cpp | 81 ++-
>> libsanitizer/sanitizer_common/sanitizer_mac.h | 21 +-
>> .../sanitizer_common/sanitizer_malloc_mac.inc | 18 +-
>> .../sanitizer_common/sanitizer_netbsd.cpp | 7 +-
>> .../sanitizer_platform_interceptors.h | 24 +
>> .../sanitizer_platform_limits_freebsd.cpp | 614 +++++++++---------
>> .../sanitizer_platform_limits_freebsd.h | 32 +-
>> .../sanitizer_platform_limits_linux.cpp | 7 +-
>> .../sanitizer_platform_limits_netbsd.cpp | 191 ++++++
>> .../sanitizer_platform_limits_netbsd.h | 33 +-
>> .../sanitizer_platform_limits_openbsd.cpp | 1 +
>> .../sanitizer_platform_limits_openbsd.h | 1 +
>> .../sanitizer_platform_limits_posix.cpp | 1 +
>> .../sanitizer_platform_limits_posix.h | 3 +-
>> .../sanitizer_platform_limits_solaris.cpp | 1 +
>> .../sanitizer_platform_limits_solaris.h | 1 +
>> .../sanitizer_common/sanitizer_posix.cpp | 10 +-
>> .../sanitizer_common/sanitizer_posix.h | 4 +-
>> .../sanitizer_posix_libcdep.cpp | 6 +-
>> .../sanitizer_common/sanitizer_procmaps.h | 7 +-
>> .../sanitizer_procmaps_fuchsia.cpp | 80 +++
>> .../sanitizer_common/sanitizer_ptrauth.h | 21 +
>> .../sanitizer_common/sanitizer_rtems.cpp | 4 +
>> .../sanitizer_common/sanitizer_stacktrace.cpp | 17 +-
>> .../sanitizer_stoptheworld_fuchsia.cpp | 42 ++
>> .../sanitizer_stoptheworld_mac.cpp | 9 +-
>> .../sanitizer_stoptheworld_netbsd_libcdep.cpp | 12 +-
>> .../sanitizer_common/sanitizer_symbolizer.cpp | 6 +
>> .../sanitizer_common/sanitizer_symbolizer.h | 3 +
>> .../sanitizer_symbolizer_internal.h | 7 +
>> .../sanitizer_symbolizer_libcdep.cpp | 89 ++-
>> .../sanitizer_symbolizer_mac.cpp | 88 ++-
>> .../sanitizer_symbolizer_mac.h | 1 +
>> .../sanitizer_symbolizer_markup.cpp | 4 +-
>> .../sanitizer_symbolizer_posix_libcdep.cpp | 16 +-
>> .../sanitizer_symbolizer_win.cpp | 2 +-
>> .../sanitizer_syscalls_netbsd.inc | 22 +-
>> .../sanitizer_common/sanitizer_win.cpp | 9 +-
>> libsanitizer/tsan/tsan_clock.cpp | 68 +-
>> libsanitizer/tsan/tsan_clock.h | 58 ++
>> libsanitizer/tsan/tsan_interceptors_posix.cpp | 21 +-
>> libsanitizer/tsan/tsan_platform.h | 1 +
>> libsanitizer/tsan/tsan_platform_mac.cpp | 10 +-
>> libsanitizer/tsan/tsan_rtl.cpp | 12 +-
>> libsanitizer/tsan/tsan_rtl.h | 4 +-
>> libsanitizer/tsan/tsan_rtl_mutex.cpp | 25 +-
>> libsanitizer/tsan/tsan_rtl_ppc64.S | 1 -
>> libsanitizer/tsan/tsan_rtl_thread.cpp | 34 +-
>> libsanitizer/tsan/tsan_stat.h | 1 +
>> libsanitizer/ubsan/ubsan_checks.inc | 6 +
>> libsanitizer/ubsan/ubsan_flags.cpp | 1 -
>> libsanitizer/ubsan/ubsan_handlers.cpp | 65 +-
>> libsanitizer/ubsan/ubsan_handlers.h | 8 -
>> libsanitizer/ubsan/ubsan_init.cpp | 2 +
>> libsanitizer/ubsan/ubsan_platform.h | 2 -
>> .../ubsan/ubsan_type_hash_itanium.cpp | 2 +
>> 107 files changed, 2551 insertions(+), 770 deletions(-)
>> create mode 100644 libsanitizer/lsan/lsan_common_fuchsia.cpp
>> create mode 100644 libsanitizer/lsan/lsan_fuchsia.cpp
>> create mode 100644 libsanitizer/lsan/lsan_fuchsia.h
>> create mode 100644 libsanitizer/lsan/lsan_posix.cpp
>> create mode 100644 libsanitizer/lsan/lsan_posix.h
>> create mode 100644
>> libsanitizer/sanitizer_common/sanitizer_common_interceptors_netbsd_compat.inc
>> create mode 100644
>> libsanitizer/sanitizer_common/sanitizer_procmaps_fuchsia.cpp
>> create mode 100644 libsanitizer/sanitizer_common/sanitizer_ptrauth.h
>> create mode 100644
>> libsanitizer/sanitizer_common/sanitizer_stoptheworld_fuchsia.cpp
>>
>> diff --git a/libsanitizer/MERGE b/libsanitizer/MERGE
>> index 49ee2c3bab8..e14e830ea7d 100644
>> --- a/libsanitizer/MERGE
>> +++ b/libsanitizer/MERGE
>> @@ -1,4 +1,4 @@
>> -82588e05cc32bb30807e480abd4e689b0dee132a
>> +b638b63b99d66786cb37336292604a2ae3490cfd
>>
>> The first line of this file holds the git revision number of the
>> last merge done from the master library sources.
>> diff --git a/libsanitizer/asan/asan_globals.cpp
>> b/libsanitizer/asan/asan_globals.cpp
>> index e045c31cd1c..9d7dbc6f264 100644
>> --- a/libsanitizer/asan/asan_globals.cpp
>> +++ b/libsanitizer/asan/asan_globals.cpp
>> @@ -154,6 +154,23 @@ static void CheckODRViolationViaIndicator(const
>> Global *g) {
>> }
>> }
>>
>> +// Check ODR violation for given global G by checking if it's
>> already poisoned.
>> +// We use this method in case compiler doesn't use private aliases
>> for global
>> +// variables.
>> +static void CheckODRViolationViaPoisoning(const Global *g) {
>> + if (__asan_region_is_poisoned(g->beg, g->size_with_redzone)) {
>> + // This check may not be enough: if the first global is much larger
>> + // the entire redzone of the second global may be within the
>> first global.
>> + for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) {
>> + if (g->beg == l->g->beg &&
>> + (flags()->detect_odr_violation >= 2 || g->size !=
>> l->g->size) &&
>> + !IsODRViolationSuppressed(g->name))
>> + ReportODRViolation(g, FindRegistrationSite(g),
>> + l->g, FindRegistrationSite(l->g));
>> + }
>> + }
>> +}
>> +
>> // Clang provides two different ways for global variables protection:
>> // it can poison the global itself or its private alias. In former
>> // case we may poison same symbol multiple times, that can help us to
>> @@ -199,6 +216,8 @@ static void RegisterGlobal(const Global *g) {
>> // where two globals with the same name are defined in
>> different modules.
>> if (UseODRIndicator(g))
>> CheckODRViolationViaIndicator(g);
>> + else
>> + CheckODRViolationViaPoisoning(g);
>> }
>> if (CanPoisonMemory())
>> PoisonRedZones(*g);
>> diff --git a/libsanitizer/asan/asan_interceptors.h
>> b/libsanitizer/asan/asan_interceptors.h
>> index b7a85fedbdf..344a64bd83d 100644
>> --- a/libsanitizer/asan/asan_interceptors.h
>> +++ b/libsanitizer/asan/asan_interceptors.h
>> @@ -80,12 +80,7 @@ void InitializePlatformInterceptors();
>> #if ASAN_HAS_EXCEPTIONS && !SANITIZER_WINDOWS && !SANITIZER_SOLARIS
>> && \
>> !SANITIZER_NETBSD
>> # define ASAN_INTERCEPT___CXA_THROW 1
>> -# if ! defined(ASAN_HAS_CXA_RETHROW_PRIMARY_EXCEPTION) \
>> - || ASAN_HAS_CXA_RETHROW_PRIMARY_EXCEPTION
>> -# define ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION 1
>> -# else
>> -# define ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION 0
>> -# endif
>> +# define ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION 1
>> # if defined(_GLIBCXX_SJLJ_EXCEPTIONS) || (SANITIZER_IOS &&
>> defined(__arm__))
>> # define ASAN_INTERCEPT__UNWIND_SJLJ_RAISEEXCEPTION 1
>> # else
>> diff --git a/libsanitizer/asan/asan_mapping.h
>> b/libsanitizer/asan/asan_mapping.h
>> index 09be904270c..41fb49ee46d 100644
>> --- a/libsanitizer/asan/asan_mapping.h
>> +++ b/libsanitizer/asan/asan_mapping.h
>> @@ -163,7 +163,7 @@ static const u64 kDefaultShort64bitShadowOffset =
>> static const u64 kAArch64_ShadowOffset64 = 1ULL << 36;
>> static const u64 kMIPS32_ShadowOffset32 = 0x0aaa0000;
>> static const u64 kMIPS64_ShadowOffset64 = 1ULL << 37;
>> -static const u64 kPPC64_ShadowOffset64 = 1ULL << 41;
>> +static const u64 kPPC64_ShadowOffset64 = 1ULL << 44;
>> static const u64 kSystemZ_ShadowOffset64 = 1ULL << 52;
>> static const u64 kSPARC64_ShadowOffset64 = 1ULL << 43; //
>> 0x80000000000
>> static const u64 kFreeBSD_ShadowOffset32 = 1ULL << 30; // 0x40000000
>> diff --git a/libsanitizer/asan/asan_report.cpp
>> b/libsanitizer/asan/asan_report.cpp
>> index 2e6ce436d03..99e8678aa78 100644
>> --- a/libsanitizer/asan/asan_report.cpp
>> +++ b/libsanitizer/asan/asan_report.cpp
>> @@ -160,6 +160,9 @@ class ScopedInErrorReport {
>> BlockingMutexLock l(&error_message_buf_mutex);
>> internal_memcpy(buffer_copy.data(),
>> error_message_buffer, kErrorMessageBufferSize);
>> + // Clear error_message_buffer so that if we find other errors
>> + // we don't re-log this error.
>> + error_message_buffer_pos = 0;
>> }
>>
>> LogFullErrorReport(buffer_copy.data());
>> diff --git a/libsanitizer/asan/asan_thread.cpp
>> b/libsanitizer/asan/asan_thread.cpp
>> index 6734d9a1668..f0df8bd4b37 100644
>> --- a/libsanitizer/asan/asan_thread.cpp
>> +++ b/libsanitizer/asan/asan_thread.cpp
>> @@ -480,6 +480,8 @@ bool GetThreadRangesLocked(tid_t os_id, uptr
>> *stack_begin, uptr *stack_end,
>> return true;
>> }
>>
>> +void GetAllThreadAllocatorCachesLocked(InternalMmapVector<uptr>
>> *caches) {}
>> +
>> void ForEachExtraStackRange(tid_t os_id, RangeIteratorCallback
>> callback,
>> void *arg) {
>> __asan::AsanThread *t = __asan::GetAsanThreadByOsIDLocked(os_id);
>> diff --git a/libsanitizer/include/sanitizer/linux_syscall_hooks.h
>> b/libsanitizer/include/sanitizer/linux_syscall_hooks.h
>> index a1794b71af5..56eae3d40f9 100644
>> --- a/libsanitizer/include/sanitizer/linux_syscall_hooks.h
>> +++ b/libsanitizer/include/sanitizer/linux_syscall_hooks.h
>> @@ -1845,6 +1845,10 @@
>> #define __sanitizer_syscall_post_rt_sigaction(res, signum, act,
>> oldact, sz) \
>> __sanitizer_syscall_post_impl_rt_sigaction(res, (long)signum,
>> (long)act, \
>> (long)oldact, (long)sz)
>> +#define __sanitizer_syscall_pre_sigaltstack(ss,
>> oss) \
>> + __sanitizer_syscall_pre_impl_sigaltstack((long)ss, (long)oss)
>> +#define __sanitizer_syscall_post_sigaltstack(res, ss,
>> oss) \
>> + __sanitizer_syscall_post_impl_sigaltstack(res, (long)ss, (long)oss)
>>
>> // And now a few syscalls we don't handle yet.
>> #define __sanitizer_syscall_pre_afs_syscall(...)
>> @@ -1912,7 +1916,6 @@
>> #define __sanitizer_syscall_pre_setreuid32(...)
>> #define __sanitizer_syscall_pre_set_thread_area(...)
>> #define __sanitizer_syscall_pre_setuid32(...)
>> -#define __sanitizer_syscall_pre_sigaltstack(...)
>> #define __sanitizer_syscall_pre_sigreturn(...)
>> #define __sanitizer_syscall_pre_sigsuspend(...)
>> #define __sanitizer_syscall_pre_stty(...)
>> @@ -1992,7 +1995,6 @@
>> #define __sanitizer_syscall_post_setreuid32(res, ...)
>> #define __sanitizer_syscall_post_set_thread_area(res, ...)
>> #define __sanitizer_syscall_post_setuid32(res, ...)
>> -#define __sanitizer_syscall_post_sigaltstack(res, ...)
>> #define __sanitizer_syscall_post_sigreturn(res, ...)
>> #define __sanitizer_syscall_post_sigsuspend(res, ...)
>> #define __sanitizer_syscall_post_stty(res, ...)
>> @@ -3075,6 +3077,8 @@ void
>> __sanitizer_syscall_pre_impl_rt_sigaction(long signum, long act,
>> long oldact, long sz);
>> void __sanitizer_syscall_post_impl_rt_sigaction(long res, long
>> signum, long act,
>> long oldact, long sz);
>> +void __sanitizer_syscall_pre_impl_sigaltstack(long ss, long oss);
>> +void __sanitizer_syscall_post_impl_sigaltstack(long res, long ss,
>> long oss);
>> #ifdef __cplusplus
>> } // extern "C"
>> #endif
>> diff --git a/libsanitizer/include/sanitizer/netbsd_syscall_hooks.h
>> b/libsanitizer/include/sanitizer/netbsd_syscall_hooks.h
>> index 174b4bf06de..370da0ea72e 100644
>> --- a/libsanitizer/include/sanitizer/netbsd_syscall_hooks.h
>> +++ b/libsanitizer/include/sanitizer/netbsd_syscall_hooks.h
>> @@ -20,7 +20,7 @@
>> // DO NOT EDIT! THIS FILE HAS BEEN GENERATED!
>> //
>> // Generated with: generate_netbsd_syscalls.awk
>> -// Generated date: 2019-11-01
>> +// Generated date: 2019-12-24
>> // Generated from: syscalls.master,v 1.296 2019/09/22 22:59:39
>> christos Exp
>> //
>> //===----------------------------------------------------------------------===//
>>
>> diff --git a/libsanitizer/include/sanitizer/tsan_interface.h
>> b/libsanitizer/include/sanitizer/tsan_interface.h
>> index 011b23350ca..96b8ad58541 100644
>> --- a/libsanitizer/include/sanitizer/tsan_interface.h
>> +++ b/libsanitizer/include/sanitizer/tsan_interface.h
>> @@ -38,34 +38,34 @@ void __tsan_release(void *addr);
>>
>> // Mutex has static storage duration and no-op constructor and
>> destructor.
>> // This effectively makes tsan ignore destroy annotation.
>> -const unsigned __tsan_mutex_linker_init = 1 << 0;
>> +static const unsigned __tsan_mutex_linker_init = 1 << 0;
>> // Mutex is write reentrant.
>> -const unsigned __tsan_mutex_write_reentrant = 1 << 1;
>> +static const unsigned __tsan_mutex_write_reentrant = 1 << 1;
>> // Mutex is read reentrant.
>> -const unsigned __tsan_mutex_read_reentrant = 1 << 2;
>> +static const unsigned __tsan_mutex_read_reentrant = 1 << 2;
>> // Mutex does not have static storage duration, and must not be
>> used after
>> // its destructor runs. The opposite of __tsan_mutex_linker_init.
>> // If this flag is passed to __tsan_mutex_destroy, then the
>> destruction
>> // is ignored unless this flag was previously set on the mutex.
>> -const unsigned __tsan_mutex_not_static = 1 << 8;
>> +static const unsigned __tsan_mutex_not_static = 1 << 8;
>>
>> // Mutex operation flags:
>>
>> // Denotes read lock operation.
>> -const unsigned __tsan_mutex_read_lock = 1 << 3;
>> +static const unsigned __tsan_mutex_read_lock = 1 << 3;
>> // Denotes try lock operation.
>> -const unsigned __tsan_mutex_try_lock = 1 << 4;
>> +static const unsigned __tsan_mutex_try_lock = 1 << 4;
>> // Denotes that a try lock operation has failed to acquire the mutex.
>> -const unsigned __tsan_mutex_try_lock_failed = 1 << 5;
>> +static const unsigned __tsan_mutex_try_lock_failed = 1 << 5;
>> // Denotes that the lock operation acquires multiple recursion levels.
>> // Number of levels is passed in recursion parameter.
>> // This is useful for annotation of e.g. Java builtin monitors,
>> // for which wait operation releases all recursive acquisitions of
>> the mutex.
>> -const unsigned __tsan_mutex_recursive_lock = 1 << 6;
>> +static const unsigned __tsan_mutex_recursive_lock = 1 << 6;
>> // Denotes that the unlock operation releases all recursion levels.
>> // Number of released levels is returned and later must be passed to
>> // the corresponding __tsan_mutex_post_lock annotation.
>> -const unsigned __tsan_mutex_recursive_unlock = 1 << 7;
>> +static const unsigned __tsan_mutex_recursive_unlock = 1 << 7;
>>
>> // Annotate creation of a mutex.
>> // Supported flags: mutex creation flags.
>> @@ -152,7 +152,7 @@ void __tsan_set_fiber_name(void *fiber, const
>> char *name);
>>
>> // Flags for __tsan_switch_to_fiber:
>> // Do not establish a happens-before relation between fibers
>> -const unsigned __tsan_switch_to_fiber_no_sync = 1 << 0;
>> +static const unsigned __tsan_switch_to_fiber_no_sync = 1 << 0;
>>
>> #ifdef __cplusplus
>> } // extern "C"
>> diff --git a/libsanitizer/lsan/lsan.cpp b/libsanitizer/lsan/lsan.cpp
>> index 4ce03046ffb..80a6e2fa701 100644
>> --- a/libsanitizer/lsan/lsan.cpp
>> +++ b/libsanitizer/lsan/lsan.cpp
>> @@ -15,7 +15,6 @@
>>
>> #include "sanitizer_common/sanitizer_flags.h"
>> #include "sanitizer_common/sanitizer_flag_parser.h"
>> -#include "sanitizer_common/sanitizer_stacktrace.h"
>> #include "lsan_allocator.h"
>> #include "lsan_common.h"
>> #include "lsan_thread.h"
>> @@ -87,17 +86,6 @@ static void InitializeFlags() {
>> __sanitizer_set_report_path(common_flags()->log_path);
>> }
>>
>> -static void OnStackUnwind(const SignalContext &sig, const void *,
>> - BufferedStackTrace *stack) {
>> - stack->Unwind(StackTrace::GetNextInstructionPc(sig.pc), sig.bp,
>> sig.context,
>> - common_flags()->fast_unwind_on_fatal);
>> -}
>> -
>> -static void LsanOnDeadlySignal(int signo, void *siginfo, void
>> *context) {
>> - HandleDeadlySignal(siginfo, context, GetCurrentThread(),
>> &OnStackUnwind,
>> - nullptr);
>> -}
>> -
>> extern "C" void __lsan_init() {
>> CHECK(!lsan_init_is_running);
>> if (lsan_inited)
>> @@ -114,10 +102,7 @@ extern "C" void __lsan_init() {
>> InitializeInterceptors();
>> InitializeThreadRegistry();
>> InstallDeadlySignalHandlers(LsanOnDeadlySignal);
>> - u32 tid = ThreadCreate(0, 0, true);
>> - CHECK_EQ(tid, 0);
>> - ThreadStart(tid, GetTid());
>> - SetCurrentThread(tid);
>> + InitializeMainThread();
>>
>> if (common_flags()->detect_leaks &&
>> common_flags()->leak_check_at_exit)
>> Atexit(DoLeakCheck);
>> diff --git a/libsanitizer/lsan/lsan.h b/libsanitizer/lsan/lsan.h
>> index 9904ada4bb3..1e82ad72f00 100644
>> --- a/libsanitizer/lsan/lsan.h
>> +++ b/libsanitizer/lsan/lsan.h
>> @@ -12,6 +12,11 @@
>> //===----------------------------------------------------------------------===//
>>
>>
>> #include "lsan_thread.h"
>> +#if SANITIZER_POSIX
>> +#include "lsan_posix.h"
>> +#elif SANITIZER_FUCHSIA
>> +#include "lsan_fuchsia.h"
>> +#endif
>> #include "sanitizer_common/sanitizer_flags.h"
>> #include "sanitizer_common/sanitizer_stacktrace.h"
>>
>> @@ -33,6 +38,7 @@ namespace __lsan {
>>
>> void InitializeInterceptors();
>> void ReplaceSystemMalloc();
>> +void LsanOnDeadlySignal(int signo, void *siginfo, void *context);
>>
>> #define ENSURE_LSAN_INITED do { \
>> CHECK(!lsan_init_is_running); \
>> diff --git a/libsanitizer/lsan/lsan_allocator.h
>> b/libsanitizer/lsan/lsan_allocator.h
>> index e1397099767..bda9d8cdf74 100644
>> --- a/libsanitizer/lsan/lsan_allocator.h
>> +++ b/libsanitizer/lsan/lsan_allocator.h
>> @@ -66,7 +66,10 @@ template <typename AddressSpaceView>
>> using PrimaryAllocatorASVT =
>> SizeClassAllocator32<AP32<AddressSpaceView>>;
>> using PrimaryAllocator = PrimaryAllocatorASVT<LocalAddressSpaceView>;
>> #elif defined(__x86_64__) || defined(__powerpc64__)
>> -# if defined(__powerpc64__)
>> +# if SANITIZER_FUCHSIA
>> +const uptr kAllocatorSpace = ~(uptr)0;
>> +const uptr kAllocatorSize = 0x40000000000ULL; // 4T.
>> +# elif defined(__powerpc64__)
>> const uptr kAllocatorSpace = 0xa0000000000ULL;
>> const uptr kAllocatorSize = 0x20000000000ULL; // 2T.
>> # else
>> diff --git a/libsanitizer/lsan/lsan_common.cpp
>> b/libsanitizer/lsan/lsan_common.cpp
>> index 9ff9f4c5d1c..32ea4e88003 100644
>> --- a/libsanitizer/lsan/lsan_common.cpp
>> +++ b/libsanitizer/lsan/lsan_common.cpp
>> @@ -211,6 +211,13 @@ void ForEachExtraStackRangeCb(uptr begin, uptr
>> end, void* arg) {
>> ScanRangeForPointers(begin, end, frontier, "FAKE STACK",
>> kReachable);
>> }
>>
>> +#if SANITIZER_FUCHSIA
>> +
>> +// Fuchsia handles all threads together with its own callback.
>> +static void ProcessThreads(SuspendedThreadsList const &, Frontier *) {}
>> +
>> +#else
>> +
>> // Scans thread data (stacks and TLS) for heap pointers.
>> static void ProcessThreads(SuspendedThreadsList const
>> &suspended_threads,
>> Frontier *frontier) {
>> @@ -308,6 +315,8 @@ static void ProcessThreads(SuspendedThreadsList
>> const &suspended_threads,
>> }
>> }
>>
>> +#endif // SANITIZER_FUCHSIA
>> +
>> void ScanRootRegion(Frontier *frontier, const RootRegion &root_region,
>> uptr region_begin, uptr region_end, bool
>> is_readable) {
>> uptr intersection_begin = Max(root_region.begin, region_begin);
>> @@ -443,25 +452,23 @@ void ProcessPC(Frontier *frontier) {
>> }
>>
>> // Sets the appropriate tag on each chunk.
>> -static void ClassifyAllChunks(SuspendedThreadsList const
>> &suspended_threads) {
>> - // Holds the flood fill frontier.
>> - Frontier frontier;
>> -
>> - ForEachChunk(CollectIgnoredCb, &frontier);
>> - ProcessGlobalRegions(&frontier);
>> - ProcessThreads(suspended_threads, &frontier);
>> - ProcessRootRegions(&frontier);
>> - FloodFillTag(&frontier, kReachable);
>> +static void ClassifyAllChunks(SuspendedThreadsList const
>> &suspended_threads,
>> + Frontier *frontier) {
>> + ForEachChunk(CollectIgnoredCb, frontier);
>> + ProcessGlobalRegions(frontier);
>> + ProcessThreads(suspended_threads, frontier);
>> + ProcessRootRegions(frontier);
>> + FloodFillTag(frontier, kReachable);
>>
>> - CHECK_EQ(0, frontier.size());
>> - ProcessPC(&frontier);
>> + CHECK_EQ(0, frontier->size());
>> + ProcessPC(frontier);
>>
>> // 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.
>> LOG_POINTERS("Processing platform-specific allocations.\n");
>> - ProcessPlatformSpecificAllocations(&frontier);
>> - FloodFillTag(&frontier, kReachable);
>> + ProcessPlatformSpecificAllocations(frontier);
>> + FloodFillTag(frontier, kReachable);
>>
>> // Iterate over leaked chunks and mark those that are reachable
>> from other
>> // leaked chunks.
>> @@ -521,11 +528,6 @@ static void PrintMatchedSuppressions() {
>> Printf("%s\n\n", line);
>> }
>>
>> -struct CheckForLeaksParam {
>> - bool success;
>> - LeakReport leak_report;
>> -};
>> -
>> static void ReportIfNotSuspended(ThreadContextBase *tctx, void *arg) {
>> const InternalMmapVector<tid_t> &suspended_threads =
>> *(const InternalMmapVector<tid_t> *)arg;
>> @@ -538,6 +540,14 @@ static void
>> ReportIfNotSuspended(ThreadContextBase *tctx, void *arg) {
>> }
>> }
>>
>> +#if SANITIZER_FUCHSIA
>> +
>> +// Fuchsia provides a libc interface that guarantees all threads are
>> +// covered, and SuspendedThreadList is never really used.
>> +static void ReportUnsuspendedThreads(const SuspendedThreadsList &) {}
>> +
>> +#else // !SANITIZER_FUCHSIA
>> +
>> static void ReportUnsuspendedThreads(
>> const SuspendedThreadsList &suspended_threads) {
>> InternalMmapVector<tid_t> threads(suspended_threads.ThreadCount());
>> @@ -550,13 +560,15 @@ static void ReportUnsuspendedThreads(
>> &ReportIfNotSuspended, &threads);
>> }
>>
>> +#endif // !SANITIZER_FUCHSIA
>> +
>> static void CheckForLeaksCallback(const SuspendedThreadsList
>> &suspended_threads,
>> void *arg) {
>> CheckForLeaksParam *param = reinterpret_cast<CheckForLeaksParam
>> *>(arg);
>> CHECK(param);
>> CHECK(!param->success);
>> ReportUnsuspendedThreads(suspended_threads);
>> - ClassifyAllChunks(suspended_threads);
>> + ClassifyAllChunks(suspended_threads, ¶m->frontier);
>> ForEachChunk(CollectLeaksCb, ¶m->leak_report);
>> // Clean up for subsequent leak checks. This assumes we did not
>> overwrite any
>> // kIgnored tags.
>> @@ -569,7 +581,6 @@ static bool CheckForLeaks() {
>> return false;
>> EnsureMainThreadIDIsCorrect();
>> CheckForLeaksParam param;
>> - param.success = false;
>> LockStuffAndStopTheWorld(CheckForLeaksCallback, ¶m);
>>
>> if (!param.success) {
>> diff --git a/libsanitizer/lsan/lsan_common.h
>> b/libsanitizer/lsan/lsan_common.h
>> index d24abe31b71..6252d52c197 100644
>> --- a/libsanitizer/lsan/lsan_common.h
>> +++ b/libsanitizer/lsan/lsan_common.h
>> @@ -40,7 +40,7 @@
>> #elif defined(__arm__) && \
>> SANITIZER_LINUX && !SANITIZER_ANDROID
>> #define CAN_SANITIZE_LEAKS 1
>> -#elif SANITIZER_NETBSD
>> +#elif SANITIZER_NETBSD || SANITIZER_FUCHSIA
>> #define CAN_SANITIZE_LEAKS 1
>> #else
>> #define CAN_SANITIZE_LEAKS 0
>> @@ -126,12 +126,24 @@ struct RootRegion {
>> uptr size;
>> };
>>
>> +// LockStuffAndStopTheWorld can start to use Scan* calls to collect
>> into
>> +// this Frontier vector before the StopTheWorldCallback actually runs.
>> +// This is used when the OS has a unified callback API for suspending
>> +// threads and enumerating roots.
>> +struct CheckForLeaksParam {
>> + Frontier frontier;
>> + LeakReport leak_report;
>> + bool success = false;
>> +};
>> +
>> InternalMmapVector<RootRegion> const *GetRootRegions();
>> void ScanRootRegion(Frontier *frontier, RootRegion const ®ion,
>> uptr region_begin, uptr region_end, bool
>> is_readable);
>> +void ForEachExtraStackRangeCb(uptr begin, uptr end, void* arg);
>> // Run stoptheworld while holding any platform-specific locks, as
>> well as the
>> // allocator and thread registry locks.
>> -void LockStuffAndStopTheWorld(StopTheWorldCallback callback, void*
>> argument);
>> +void LockStuffAndStopTheWorld(StopTheWorldCallback callback,
>> + CheckForLeaksParam* argument);
>>
>> void ScanRangeForPointers(uptr begin, uptr end,
>> Frontier *frontier,
>> @@ -211,6 +223,7 @@ ThreadRegistry *GetThreadRegistryLocked();
>> bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr
>> *stack_end,
>> uptr *tls_begin, uptr *tls_end, uptr
>> *cache_begin,
>> uptr *cache_end, DTLS **dtls);
>> +void GetAllThreadAllocatorCachesLocked(InternalMmapVector<uptr>
>> *caches);
>> void ForEachExtraStackRange(tid_t os_id, RangeIteratorCallback
>> callback,
>> void *arg);
>> // If called from the main thread, updates the main thread's TID in
>> the thread
>> diff --git a/libsanitizer/lsan/lsan_common_fuchsia.cpp
>> b/libsanitizer/lsan/lsan_common_fuchsia.cpp
>> new file mode 100644
>> index 00000000000..caedbf15596
>> --- /dev/null
>> +++ b/libsanitizer/lsan/lsan_common_fuchsia.cpp
>> @@ -0,0 +1,166 @@
>> +//=-- lsan_common_fuchsia.cpp
>> --------------------------------------------===//
>> +//
>> +// Part of the LLVM Project, under the Apache License v2.0 with LLVM
>> Exceptions.
>> +// See https://llvm.org/LICENSE.txt for license information.
>> +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
>> +//
>> +//===---------------------------------------------------------------------===//
>>
>> +//
>> +// This file is a part of LeakSanitizer.
>> +// Implementation of common leak checking functionality.
>> Fuchsia-specific code.
>> +//
>> +//===---------------------------------------------------------------------===//
>>
>> +
>> +#include "lsan_common.h"
>> +#include "sanitizer_common/sanitizer_platform.h"
>> +
>> +#if CAN_SANITIZE_LEAKS && SANITIZER_FUCHSIA
>> +#include <zircon/sanitizer.h>
>> +
>> +#include "lsan_allocator.h"
>> +#include "sanitizer_common/sanitizer_flags.h"
>> +#include "sanitizer_common/sanitizer_thread_registry.h"
>> +
>> +// Ensure that the Zircon system ABI is linked in.
>> +#pragma comment(lib, "zircon")
>> +
>> +namespace __lsan {
>> +
>> +void InitializePlatformSpecificModules() {}
>> +
>> +LoadedModule *GetLinker() { return nullptr; }
>> +
>> +__attribute__((tls_model("initial-exec"))) THREADLOCAL int
>> disable_counter;
>> +bool DisabledInThisThread() { return disable_counter > 0; }
>> +void DisableInThisThread() { disable_counter++; }
>> +void EnableInThisThread() {
>> + if (disable_counter == 0) {
>> + DisableCounterUnderflow();
>> + }
>> + disable_counter--;
>> +}
>> +
>> +// There is nothing left to do after the globals callbacks.
>> +void ProcessGlobalRegions(Frontier *frontier) {}
>> +
>> +// Nothing to do here.
>> +void ProcessPlatformSpecificAllocations(Frontier *frontier) {}
>> +
>> +// On Fuchsia, we can intercept _Exit gracefully, and return a
>> failing exit
>> +// code if required at that point. Calling Die() here is undefined
>> +// behavior and causes rare race conditions.
>> +void HandleLeaks() {}
>> +
>> +int ExitHook(int status) {
>> + return status == 0 && HasReportedLeaks() ?
>> common_flags()->exitcode : status;
>> +}
>> +
>> +void LockStuffAndStopTheWorld(StopTheWorldCallback callback,
>> + CheckForLeaksParam *argument) {
>> + LockThreadRegistry();
>> + LockAllocator();
>> +
>> + struct Params {
>> + InternalMmapVector<uptr> allocator_caches;
>> + StopTheWorldCallback callback;
>> + CheckForLeaksParam *argument;
>> + } params = {{}, callback, argument};
>> +
>> + // Callback from libc for globals (data/bss modulo relro), when
>> enabled.
>> + auto globals = +[](void *chunk, size_t size, void *data) {
>> + auto params = static_cast<const Params *>(data);
>> + uptr begin = reinterpret_cast<uptr>(chunk);
>> + uptr end = begin + size;
>> + ScanGlobalRange(begin, end, ¶ms->argument->frontier);
>> + };
>> +
>> + // Callback from libc for thread stacks.
>> + auto stacks = +[](void *chunk, size_t size, void *data) {
>> + auto params = static_cast<const Params *>(data);
>> + uptr begin = reinterpret_cast<uptr>(chunk);
>> + uptr end = begin + size;
>> + ScanRangeForPointers(begin, end, ¶ms->argument->frontier,
>> "STACK",
>> + kReachable);
>> + };
>> +
>> + // Callback from libc for thread registers.
>> + auto registers = +[](void *chunk, size_t size, void *data) {
>> + auto params = static_cast<const Params *>(data);
>> + uptr begin = reinterpret_cast<uptr>(chunk);
>> + uptr end = begin + size;
>> + ScanRangeForPointers(begin, end, ¶ms->argument->frontier,
>> "REGISTERS",
>> + kReachable);
>> + };
>> +
>> + if (flags()->use_tls) {
>> + // Collect the allocator cache range from each thread so these
>> + // can all be excluded from the reported TLS ranges.
>> + GetAllThreadAllocatorCachesLocked(¶ms.allocator_caches);
>> + __sanitizer::Sort(params.allocator_caches.data(),
>> + params.allocator_caches.size());
>> + }
>> +
>> + // Callback from libc for TLS regions. This includes thread_local
>> + // variables as well as C11 tss_set and POSIX pthread_setspecific.
>> + auto tls = +[](void *chunk, size_t size, void *data) {
>> + auto params = static_cast<const Params *>(data);
>> + uptr begin = reinterpret_cast<uptr>(chunk);
>> + uptr end = begin + size;
>> + auto i =
>> __sanitizer::InternalLowerBound(params->allocator_caches, 0,
>> + params->allocator_caches.size(),
>> + begin,
>> CompareLess<uptr>());
>> + if (i < params->allocator_caches.size() &&
>> + params->allocator_caches[i] >= begin &&
>> + end - params->allocator_caches[i] <= sizeof(AllocatorCache)) {
>> + // Split the range in two and omit the allocator cache within.
>> + ScanRangeForPointers(begin, params->allocator_caches[i],
>> + ¶ms->argument->frontier, "TLS", kReachable);
>> + uptr begin2 = params->allocator_caches[i] +
>> sizeof(AllocatorCache);
>> + ScanRangeForPointers(begin2, end, ¶ms->argument->frontier,
>> "TLS",
>> + kReachable);
>> + } else {
>> + ScanRangeForPointers(begin, end, ¶ms->argument->frontier,
>> "TLS",
>> + kReachable);
>> + }
>> + };
>> +
>> + // This stops the world and then makes callbacks for various
>> memory regions.
>> + // The final callback is the last thing before the world starts up
>> again.
>> + __sanitizer_memory_snapshot(
>> + flags()->use_globals ? globals : nullptr,
>> + flags()->use_stacks ? stacks : nullptr,
>> + flags()->use_registers ? registers : nullptr,
>> + flags()->use_tls ? tls : nullptr,
>> + [](zx_status_t, void *data) {
>> + auto params = static_cast<const Params *>(data);
>> +
>> + // We don't use the thread registry at all for enumerating
>> the threads
>> + // and their stacks, registers, and TLS regions. So use it
>> separately
>> + // just for the allocator cache, and to call
>> ForEachExtraStackRange,
>> + // which ASan needs.
>> + if (flags()->use_stacks) {
>> + GetThreadRegistryLocked()->RunCallbackForEachThreadLocked(
>> + [](ThreadContextBase *tctx, void *arg) {
>> + ForEachExtraStackRange(tctx->os_id,
>> ForEachExtraStackRangeCb,
>> + arg);
>> + },
>> + ¶ms->argument->frontier);
>> + }
>> +
>> + params->callback({}, params->argument);
>> + },
>> + ¶ms);
>> +
>> + UnlockAllocator();
>> + UnlockThreadRegistry();
>> +}
>> +
>> +} // namespace __lsan
>> +
>> +// This is declared (in extern "C") by <zircon/sanitizer.h>.
>> +// _Exit calls this directly to intercept and change the status value.
>> +int __sanitizer_process_exit_hook(int status) {
>> + return __lsan::ExitHook(status);
>> +}
>> +
>> +#endif
>> diff --git a/libsanitizer/lsan/lsan_common_linux.cpp
>> b/libsanitizer/lsan/lsan_common_linux.cpp
>> index ea1a4a2f569..c97ef31593d 100644
>> --- a/libsanitizer/lsan/lsan_common_linux.cpp
>> +++ b/libsanitizer/lsan/lsan_common_linux.cpp
>> @@ -134,7 +134,8 @@ static int
>> LockStuffAndStopTheWorldCallback(struct dl_phdr_info *info,
>> // while holding the libdl lock in the parent thread, we can safely
>> reenter it
>> // in the tracer. The solution is to run stoptheworld from a
>> dl_iterate_phdr()
>> // callback in the parent thread.
>> -void LockStuffAndStopTheWorld(StopTheWorldCallback callback, void
>> *argument) {
>> +void LockStuffAndStopTheWorld(StopTheWorldCallback callback,
>> + CheckForLeaksParam *argument) {
>> DoStopTheWorldParam param = {callback, argument};
>> dl_iterate_phdr(LockStuffAndStopTheWorldCallback, ¶m);
>> }
>> diff --git a/libsanitizer/lsan/lsan_common_mac.cpp
>> b/libsanitizer/lsan/lsan_common_mac.cpp
>> index c1804e93c11..8516a176eb4 100644
>> --- a/libsanitizer/lsan/lsan_common_mac.cpp
>> +++ b/libsanitizer/lsan/lsan_common_mac.cpp
>> @@ -193,7 +193,8 @@ void ProcessPlatformSpecificAllocations(Frontier
>> *frontier) {
>> // causes rare race conditions.
>> void HandleLeaks() {}
>>
>> -void LockStuffAndStopTheWorld(StopTheWorldCallback callback, void
>> *argument) {
>> +void LockStuffAndStopTheWorld(StopTheWorldCallback callback,
>> + CheckForLeaksParam *argument) {
>> LockThreadRegistry();
>> LockAllocator();
>> StopTheWorld(callback, argument);
>> diff --git a/libsanitizer/lsan/lsan_fuchsia.cpp
>> b/libsanitizer/lsan/lsan_fuchsia.cpp
>> new file mode 100644
>> index 00000000000..40e65c6fb72
>> --- /dev/null
>> +++ b/libsanitizer/lsan/lsan_fuchsia.cpp
>> @@ -0,0 +1,123 @@
>> +//=-- lsan_fuchsia.cpp
>> ---------------------------------------------------===//
>> +//
>> +// Part of the LLVM Project, under the Apache License v2.0 with LLVM
>> Exceptions.
>> +// See https://llvm.org/LICENSE.txt for license information.
>> +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
>> +//
>> +//===---------------------------------------------------------------------===//
>>
>> +//
>> +// This file is a part of LeakSanitizer.
>> +// Standalone LSan RTL code specific to Fuchsia.
>> +//
>> +//===---------------------------------------------------------------------===//
>>
>> +
>> +#include "sanitizer_common/sanitizer_platform.h"
>> +
>> +#if SANITIZER_FUCHSIA
>> +#include <zircon/sanitizer.h>
>> +
>> +#include "lsan.h"
>> +#include "lsan_allocator.h"
>> +
>> +using namespace __lsan;
>> +
>> +namespace __lsan {
>> +
>> +void LsanOnDeadlySignal(int signo, void *siginfo, void *context) {}
>> +
>> +ThreadContext::ThreadContext(int tid) : ThreadContextLsanBase(tid) {}
>> +
>> +struct OnCreatedArgs {
>> + uptr stack_begin, stack_end;
>> +};
>> +
>> +// On Fuchsia, the stack bounds of a new thread are available before
>> +// the thread itself has started running.
>> +void ThreadContext::OnCreated(void *arg) {
>> + // Stack bounds passed through from
>> __sanitizer_before_thread_create_hook
>> + // or InitializeMainThread.
>> + auto args = reinterpret_cast<const OnCreatedArgs *>(arg);
>> + stack_begin_ = args->stack_begin;
>> + stack_end_ = args->stack_end;
>> +}
>> +
>> +struct OnStartedArgs {
>> + uptr cache_begin, cache_end;
>> +};
>> +
>> +void ThreadContext::OnStarted(void *arg) {
>> + auto args = reinterpret_cast<const OnStartedArgs *>(arg);
>> + cache_begin_ = args->cache_begin;
>> + cache_end_ = args->cache_end;
>> +}
>> +
>> +void ThreadStart(u32 tid) {
>> + OnStartedArgs args;
>> + GetAllocatorCacheRange(&args.cache_begin, &args.cache_end);
>> + CHECK_EQ(args.cache_end - args.cache_begin, sizeof(AllocatorCache));
>> + ThreadContextLsanBase::ThreadStart(tid, GetTid(),
>> ThreadType::Regular, &args);
>> +}
>> +
>> +void InitializeMainThread() {
>> + OnCreatedArgs args;
>> + __sanitizer::GetThreadStackTopAndBottom(true, &args.stack_end,
>> + &args.stack_begin);
>> + u32 tid = ThreadCreate(0, GetThreadSelf(), true, &args);
>> + CHECK_EQ(tid, 0);
>> + ThreadStart(tid);
>> +}
>> +
>> +void GetAllThreadAllocatorCachesLocked(InternalMmapVector<uptr>
>> *caches) {
>> + GetThreadRegistryLocked()->RunCallbackForEachThreadLocked(
>> + [](ThreadContextBase *tctx, void *arg) {
>> + auto ctx = static_cast<ThreadContext *>(tctx);
>> + static_cast<decltype(caches)>(arg)->push_back(ctx->cache_begin());
>> + },
>> + caches);
>> +}
>> +
>> +} // namespace __lsan
>> +
>> +// These are declared (in extern "C") by <zircon/sanitizer.h>.
>> +// The system runtime will call our definitions directly.
>> +
>> +// This is called before each thread creation is attempted. So, in
>> +// its first call, the calling thread is the initial and sole thread.
>> +void *__sanitizer_before_thread_create_hook(thrd_t thread, bool
>> detached,
>> + const char *name, void
>> *stack_base,
>> + size_t stack_size) {
>> + uptr user_id = reinterpret_cast<uptr>(thread);
>> + ENSURE_LSAN_INITED;
>> + EnsureMainThreadIDIsCorrect();
>> + OnCreatedArgs args;
>> + args.stack_begin = reinterpret_cast<uptr>(stack_base);
>> + args.stack_end = args.stack_begin + stack_size;
>> + u32 parent_tid = GetCurrentThread();
>> + u32 tid = ThreadCreate(parent_tid, user_id, detached, &args);
>> + return reinterpret_cast<void *>(static_cast<uptr>(tid));
>> +}
>> +
>> +// This is called after creating a new thread (in the creating thread),
>> +// with the pointer returned by
>> __sanitizer_before_thread_create_hook (above).
>> +void __sanitizer_thread_create_hook(void *hook, thrd_t thread, int
>> error) {
>> + u32 tid = static_cast<u32>(reinterpret_cast<uptr>(hook));
>> + // On success, there is nothing to do here.
>> + if (error != thrd_success) {
>> + // Clean up the thread registry for the thread creation that
>> didn't happen.
>> + GetThreadRegistryLocked()->FinishThread(tid);
>> + }
>> +}
>> +
>> +// This is called in the newly-created thread before it runs
>> anything else,
>> +// with the pointer returned by
>> __sanitizer_before_thread_create_hook (above).
>> +void __sanitizer_thread_start_hook(void *hook, thrd_t self) {
>> + u32 tid = static_cast<u32>(reinterpret_cast<uptr>(hook));
>> + ThreadStart(tid);
>> +}
>> +
>> +// Each thread runs this just before it exits,
>> +// with the pointer returned by BeforeThreadCreateHook (above).
>> +// All per-thread destructors have already been called.
>> +void __sanitizer_thread_exit_hook(void *hook, thrd_t self) {
>> ThreadFinish(); }
>> +
>> +#endif // SANITIZER_FUCHSIA
>> diff --git a/libsanitizer/lsan/lsan_fuchsia.h
>> b/libsanitizer/lsan/lsan_fuchsia.h
>> new file mode 100644
>> index 00000000000..65d20ea2114
>> --- /dev/null
>> +++ b/libsanitizer/lsan/lsan_fuchsia.h
>> @@ -0,0 +1,35 @@
>> +//=-- lsan_fuchsia.h
>> ---------------------------------------------------===//
>> +//
>> +// Part of the LLVM Project, under the Apache License v2.0 with LLVM
>> Exceptions.
>> +// See https://llvm.org/LICENSE.txt for license information.
>> +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
>> +//
>> +//===---------------------------------------------------------------------===//
>>
>> +//
>> +// This file is a part of LeakSanitizer.
>> +// Standalone LSan RTL code specific to Fuchsia.
>> +//
>> +//===---------------------------------------------------------------------===//
>>
>> +
>> +#ifndef LSAN_FUCHSIA_H
>> +#define LSAN_FUCHSIA_H
>> +
>> +#include "lsan_thread.h"
>> +#include "sanitizer_common/sanitizer_platform.h"
>> +
>> +#if !SANITIZER_FUCHSIA
>> +#error "lsan_fuchsia.h is used only on Fuchsia systems
>> (SANITIZER_FUCHSIA)"
>> +#endif
>> +
>> +namespace __lsan {
>> +
>> +class ThreadContext : public ThreadContextLsanBase {
>> + public:
>> + explicit ThreadContext(int tid);
>> + void OnCreated(void *arg) override;
>> + void OnStarted(void *arg) override;
>> +};
>> +
>> +} // namespace __lsan
>> +
>> +#endif // LSAN_FUCHSIA_H
>> diff --git a/libsanitizer/lsan/lsan_interceptors.cpp
>> b/libsanitizer/lsan/lsan_interceptors.cpp
>> index f642bb807bc..9ce9b78c5a5 100644
>> --- a/libsanitizer/lsan/lsan_interceptors.cpp
>> +++ b/libsanitizer/lsan/lsan_interceptors.cpp
>> @@ -22,7 +22,9 @@
>> #include "sanitizer_common/sanitizer_platform_interceptors.h"
>> #include "sanitizer_common/sanitizer_platform_limits_netbsd.h"
>> #include "sanitizer_common/sanitizer_platform_limits_posix.h"
>> +#if SANITIZER_POSIX
>> #include "sanitizer_common/sanitizer_posix.h"
>> +#endif
>> #include "sanitizer_common/sanitizer_tls_get_addr.h"
>> #include "lsan.h"
>> #include "lsan_allocator.h"
>> @@ -61,6 +63,9 @@ INTERCEPTOR(void, free, void *p) {
>> }
>>
>> INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {
>> + // This hack is not required for Fuchsia because there are no
>> dlsym calls
>> + // involved in setting up interceptors.
>> +#if !SANITIZER_FUCHSIA
>> if (lsan_init_is_running) {
>> // Hack: dlsym calls calloc before REAL(calloc) is retrieved
>> from dlsym.
>> const uptr kCallocPoolSize = 1024;
>> @@ -72,6 +77,7 @@ INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {
>> CHECK(allocated < kCallocPoolSize);
>> return mem;
>> }
>> +#endif // !SANITIZER_FUCHSIA
>> ENSURE_LSAN_INITED;
>> GET_STACK_TRACE_MALLOC;
>> return lsan_calloc(nmemb, size, stack);
>> @@ -100,7 +106,7 @@ INTERCEPTOR(void*, valloc, uptr size) {
>> GET_STACK_TRACE_MALLOC;
>> return lsan_valloc(size, stack);
>> }
>> -#endif
>> +#endif // !SANITIZER_MAC
>>
>> #if SANITIZER_INTERCEPT_MEMALIGN
>> INTERCEPTOR(void*, memalign, uptr alignment, uptr size) {
>> @@ -307,7 +313,7 @@ INTERCEPTOR(void, _ZdaPvRKSt9nothrow_t, void
>> *ptr, std::nothrow_t const&)
>>
>> ///// Thread initialization and finalization. /////
>>
>> -#if !SANITIZER_NETBSD && !SANITIZER_FREEBSD
>> +#if !SANITIZER_NETBSD && !SANITIZER_FREEBSD && !SANITIZER_FUCHSIA
>> static unsigned g_thread_finalize_key;
>>
>> static void thread_finalize(void *v) {
>> @@ -394,6 +400,8 @@ INTERCEPTOR(char *, strerror, int errnum) {
>> #define LSAN_MAYBE_INTERCEPT_STRERROR
>> #endif
>>
>> +#if SANITIZER_POSIX
>> +
>> struct ThreadParam {
>> void *(*callback)(void *arg);
>> void *param;
>> @@ -416,7 +424,6 @@ extern "C" void *__lsan_thread_start_func(void
>> *arg) {
>> int tid = 0;
>> while ((tid = atomic_load(&p->tid, memory_order_acquire)) == 0)
>> internal_sched_yield();
>> - SetCurrentThread(tid);
>> ThreadStart(tid, GetTid());
>> atomic_store(&p->tid, 0, memory_order_release);
>> return callback(param);
>> @@ -477,9 +484,13 @@ INTERCEPTOR(void, _exit, int status) {
>> #define COMMON_INTERCEPT_FUNCTION(name) INTERCEPT_FUNCTION(name)
>> #include "sanitizer_common/sanitizer_signal_interceptors.inc"
>>
>> +#endif // SANITIZER_POSIX
>> +
>> namespace __lsan {
>>
>> void InitializeInterceptors() {
>> + // Fuchsia doesn't use interceptors that require any setup.
>> +#if !SANITIZER_FUCHSIA
>> InitializeSignalInterceptors();
>>
>> INTERCEPT_FUNCTION(malloc);
>> @@ -515,6 +526,8 @@ void InitializeInterceptors() {
>> Die();
>> }
>> #endif
>> +
>> +#endif // !SANITIZER_FUCHSIA
>> }
>>
>> } // namespace __lsan
>> diff --git a/libsanitizer/lsan/lsan_linux.cpp
>> b/libsanitizer/lsan/lsan_linux.cpp
>> index 14a42b75d2a..47c2f21b5a6 100644
>> --- a/libsanitizer/lsan/lsan_linux.cpp
>> +++ b/libsanitizer/lsan/lsan_linux.cpp
>> @@ -6,13 +6,13 @@
>> //
>> //===----------------------------------------------------------------------===//
>>
>> //
>> -// This file is a part of LeakSanitizer. Linux/NetBSD-specific code.
>> +// This file is a part of LeakSanitizer.
>> Linux/NetBSD/Fuchsia-specific code.
>> //
>> //===----------------------------------------------------------------------===//
>>
>>
>> #include "sanitizer_common/sanitizer_platform.h"
>>
>> -#if SANITIZER_LINUX || SANITIZER_NETBSD
>> +#if SANITIZER_LINUX || SANITIZER_NETBSD || SANITIZER_FUCHSIA
>>
>> #include "lsan_allocator.h"
>>
>> @@ -29,4 +29,4 @@ void ReplaceSystemMalloc() {}
>>
>> } // namespace __lsan
>>
>> -#endif // SANITIZER_LINUX || SANITIZER_NETBSD
>> +#endif // SANITIZER_LINUX || SANITIZER_NETBSD || SANITIZER_FUCHSIA
>> diff --git a/libsanitizer/lsan/lsan_posix.cpp
>> b/libsanitizer/lsan/lsan_posix.cpp
>> new file mode 100644
>> index 00000000000..8e05915dd1b
>> --- /dev/null
>> +++ b/libsanitizer/lsan/lsan_posix.cpp
>> @@ -0,0 +1,96 @@
>> +//=-- lsan_posix.cpp
>> -----------------------------------------------------===//
>> +//
>> +// Part of the LLVM Project, under the Apache License v2.0 with LLVM
>> Exceptions.
>> +// See https://llvm.org/LICENSE.txt for license information.
>> +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
>> +//
>> +//===---------------------------------------------------------------------===//
>>
>> +//
>> +// This file is a part of LeakSanitizer.
>> +// Standalone LSan RTL code common to POSIX-like systems.
>> +//
>> +//===---------------------------------------------------------------------===//
>>
>> +
>> +#include "sanitizer_common/sanitizer_platform.h"
>> +
>> +#if SANITIZER_POSIX
>> +#include "lsan.h"
>> +#include "lsan_allocator.h"
>> +#include "sanitizer_common/sanitizer_stacktrace.h"
>> +#include "sanitizer_common/sanitizer_tls_get_addr.h"
>> +
>> +namespace __lsan {
>> +
>> +ThreadContext::ThreadContext(int tid) : ThreadContextLsanBase(tid) {}
>> +
>> +struct OnStartedArgs {
>> + uptr stack_begin;
>> + uptr stack_end;
>> + uptr cache_begin;
>> + uptr cache_end;
>> + uptr tls_begin;
>> + uptr tls_end;
>> + DTLS *dtls;
>> +};
>> +
>> +void ThreadContext::OnStarted(void *arg) {
>> + auto args = reinterpret_cast<const OnStartedArgs *>(arg);
>> + stack_begin_ = args->stack_begin;
>> + stack_end_ = args->stack_end;
>> + tls_begin_ = args->tls_begin;
>> + tls_end_ = args->tls_end;
>> + cache_begin_ = args->cache_begin;
>> + cache_end_ = args->cache_end;
>> + dtls_ = args->dtls;
>> +}
>> +
>> +void ThreadStart(u32 tid, tid_t os_id, ThreadType thread_type) {
>> + OnStartedArgs args;
>> + uptr stack_size = 0;
>> + uptr tls_size = 0;
>> + GetThreadStackAndTls(tid == 0, &args.stack_begin, &stack_size,
>> + &args.tls_begin, &tls_size);
>> + args.stack_end = args.stack_begin + stack_size;
>> + args.tls_end = args.tls_begin + tls_size;
>> + GetAllocatorCacheRange(&args.cache_begin, &args.cache_end);
>> + args.dtls = DTLS_Get();
>> + ThreadContextLsanBase::ThreadStart(tid, os_id, thread_type, &args);
>> +}
>> +
>> +bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr
>> *stack_end,
>> + uptr *tls_begin, uptr *tls_end, uptr
>> *cache_begin,
>> + uptr *cache_end, DTLS **dtls) {
>> + ThreadContext *context = static_cast<ThreadContext *>(
>> + GetThreadRegistryLocked()->FindThreadContextByOsIDLocked(os_id));
>> + if (!context)
>> + return false;
>> + *stack_begin = context->stack_begin();
>> + *stack_end = context->stack_end();
>> + *tls_begin = context->tls_begin();
>> + *tls_end = context->tls_end();
>> + *cache_begin = context->cache_begin();
>> + *cache_end = context->cache_end();
>> + *dtls = context->dtls();
>> + return true;
>> +}
>> +
>> +void InitializeMainThread() {
>> + u32 tid = ThreadCreate(0, 0, true);
>> + CHECK_EQ(tid, 0);
>> + ThreadStart(tid, GetTid());
>> +}
>> +
>> +static void OnStackUnwind(const SignalContext &sig, const void *,
>> + BufferedStackTrace *stack) {
>> + stack->Unwind(StackTrace::GetNextInstructionPc(sig.pc), sig.bp,
>> sig.context,
>> + common_flags()->fast_unwind_on_fatal);
>> +}
>> +
>> +void LsanOnDeadlySignal(int signo, void *siginfo, void *context) {
>> + HandleDeadlySignal(siginfo, context, GetCurrentThread(),
>> &OnStackUnwind,
>> + nullptr);
>> +}
>> +
>> +} // namespace __lsan
>> +
>> +#endif // SANITIZER_POSIX
>> diff --git a/libsanitizer/lsan/lsan_posix.h
>> b/libsanitizer/lsan/lsan_posix.h
>> new file mode 100644
>> index 00000000000..840e427c55e
>> --- /dev/null
>> +++ b/libsanitizer/lsan/lsan_posix.h
>> @@ -0,0 +1,49 @@
>> +//=-- lsan_posix.h
>> -----------------------------------------------------===//
>> +//
>> +// Part of the LLVM Project, under the Apache License v2.0 with LLVM
>> Exceptions.
>> +// See https://llvm.org/LICENSE.txt for license information.
>> +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
>> +//
>> +//===---------------------------------------------------------------------===//
>>
>> +//
>> +// This file is a part of LeakSanitizer.
>> +// Standalone LSan RTL code common to POSIX-like systems.
>> +//
>> +//===---------------------------------------------------------------------===//
>>
>> +
>> +#ifndef LSAN_POSIX_H
>> +#define LSAN_POSIX_H
>> +
>> +#include "lsan_thread.h"
>> +#include "sanitizer_common/sanitizer_platform.h"
>> +
>> +#if !SANITIZER_POSIX
>> +#error "lsan_posix.h is used only on POSIX-like systems
>> (SANITIZER_POSIX)"
>> +#endif
>> +
>> +namespace __sanitizer {
>> +struct DTLS;
>> +}
>> +
>> +namespace __lsan {
>> +
>> +class ThreadContext : public ThreadContextLsanBase {
>> + public:
>> + explicit ThreadContext(int tid);
>> + void OnStarted(void *arg) override;
>> + uptr tls_begin() { return tls_begin_; }
>> + uptr tls_end() { return tls_end_; }
>> + DTLS *dtls() { return dtls_; }
>> +
>> + private:
>> + uptr tls_begin_ = 0;
>> + uptr tls_end_ = 0;
>> + DTLS *dtls_ = nullptr;
>> +};
>> +
>> +void ThreadStart(u32 tid, tid_t os_id,
>> + ThreadType thread_type = ThreadType::Regular);
>> +
>> +} // namespace __lsan
>> +
>> +#endif // LSAN_POSIX_H
>> diff --git a/libsanitizer/lsan/lsan_thread.cpp
>> b/libsanitizer/lsan/lsan_thread.cpp
>> index 84e7ce61b97..40bdc254bb6 100644
>> --- a/libsanitizer/lsan/lsan_thread.cpp
>> +++ b/libsanitizer/lsan/lsan_thread.cpp
>> @@ -13,12 +13,13 @@
>>
>> #include "lsan_thread.h"
>>
>> +#include "lsan.h"
>> +#include "lsan_allocator.h"
>> +#include "lsan_common.h"
>> #include "sanitizer_common/sanitizer_common.h"
>> #include "sanitizer_common/sanitizer_placement_new.h"
>> #include "sanitizer_common/sanitizer_thread_registry.h"
>> #include "sanitizer_common/sanitizer_tls_get_addr.h"
>> -#include "lsan_allocator.h"
>> -#include "lsan_common.h"
>>
>> namespace __lsan {
>>
>> @@ -26,7 +27,7 @@ static ThreadRegistry *thread_registry;
>>
>> static ThreadContextBase *CreateThreadContext(u32 tid) {
>> void *mem = MmapOrDie(sizeof(ThreadContext), "ThreadContext");
>> - return new(mem) ThreadContext(tid);
>> + return new (mem) ThreadContext(tid);
>> }
>>
>> static const uptr kMaxThreads = 1 << 13;
>> @@ -34,59 +35,26 @@ static const uptr kThreadQuarantineSize = 64;
>>
>> void InitializeThreadRegistry() {
>> static ALIGNED(64) char
>> thread_registry_placeholder[sizeof(ThreadRegistry)];
>> - thread_registry = new(thread_registry_placeholder)
>> - ThreadRegistry(CreateThreadContext, kMaxThreads,
>> kThreadQuarantineSize);
>> + thread_registry = new (thread_registry_placeholder)
>> + ThreadRegistry(CreateThreadContext, kMaxThreads,
>> kThreadQuarantineSize);
>> }
>>
>> -ThreadContext::ThreadContext(int tid)
>> - : ThreadContextBase(tid),
>> - stack_begin_(0),
>> - stack_end_(0),
>> - cache_begin_(0),
>> - cache_end_(0),
>> - tls_begin_(0),
>> - tls_end_(0),
>> - dtls_(nullptr) {}
>> -
>> -struct OnStartedArgs {
>> - uptr stack_begin, stack_end,
>> - cache_begin, cache_end,
>> - tls_begin, tls_end;
>> - DTLS *dtls;
>> -};
>> -
>> -void ThreadContext::OnStarted(void *arg) {
>> - OnStartedArgs *args = reinterpret_cast<OnStartedArgs *>(arg);
>> - stack_begin_ = args->stack_begin;
>> - stack_end_ = args->stack_end;
>> - tls_begin_ = args->tls_begin;
>> - tls_end_ = args->tls_end;
>> - cache_begin_ = args->cache_begin;
>> - cache_end_ = args->cache_end;
>> - dtls_ = args->dtls;
>> -}
>> +ThreadContextLsanBase::ThreadContextLsanBase(int tid)
>> + : ThreadContextBase(tid) {}
>>
>> -void ThreadContext::OnFinished() {
>> +void ThreadContextLsanBase::OnFinished() {
>> AllocatorThreadFinish();
>> DTLS_Destroy();
>> }
>>
>> -u32 ThreadCreate(u32 parent_tid, uptr user_id, bool detached) {
>> - return thread_registry->CreateThread(user_id, detached, parent_tid,
>> - /* arg */ nullptr);
>> +u32 ThreadCreate(u32 parent_tid, uptr user_id, bool detached, void
>> *arg) {
>> + return thread_registry->CreateThread(user_id, detached,
>> parent_tid, arg);
>> }
>>
>> -void ThreadStart(u32 tid, tid_t os_id, ThreadType thread_type) {
>> - OnStartedArgs args;
>> - uptr stack_size = 0;
>> - uptr tls_size = 0;
>> - GetThreadStackAndTls(tid == 0, &args.stack_begin, &stack_size,
>> - &args.tls_begin, &tls_size);
>> - args.stack_end = args.stack_begin + stack_size;
>> - args.tls_end = args.tls_begin + tls_size;
>> - GetAllocatorCacheRange(&args.cache_begin, &args.cache_end);
>> - args.dtls = DTLS_Get();
>> - thread_registry->StartThread(tid, os_id, thread_type, &args);
>> +void ThreadContextLsanBase::ThreadStart(u32 tid, tid_t os_id,
>> + ThreadType thread_type, void
>> *arg) {
>> + thread_registry->StartThread(tid, os_id, thread_type, arg);
>> + SetCurrentThread(tid);
>> }
>>
>> void ThreadFinish() {
>> @@ -95,7 +63,8 @@ void ThreadFinish() {
>> }
>>
>> ThreadContext *CurrentThreadContext() {
>> - if (!thread_registry) return nullptr;
>> + if (!thread_registry)
>> + return nullptr;
>> if (GetCurrentThread() == kInvalidTid)
>> return nullptr;
>> // No lock needed when getting current thread.
>> @@ -111,12 +80,12 @@ static bool FindThreadByUid(ThreadContextBase
>> *tctx, void *arg) {
>> }
>>
>> u32 ThreadTid(uptr uid) {
>> - return thread_registry->FindThread(FindThreadByUid, (void*)uid);
>> + return thread_registry->FindThread(FindThreadByUid, (void *)uid);
>> }
>>
>> void ThreadJoin(u32 tid) {
>> CHECK_NE(tid, kInvalidTid);
>> - thread_registry->JoinThread(tid, /* arg */nullptr);
>> + thread_registry->JoinThread(tid, /* arg */ nullptr);
>> }
>>
>> void EnsureMainThreadIDIsCorrect() {
>> @@ -126,37 +95,16 @@ void EnsureMainThreadIDIsCorrect() {
>>
>> ///// Interface to the common LSan module. /////
>>
>> -bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr
>> *stack_end,
>> - uptr *tls_begin, uptr *tls_end, uptr
>> *cache_begin,
>> - uptr *cache_end, DTLS **dtls) {
>> - ThreadContext *context = static_cast<ThreadContext *>(
>> - thread_registry->FindThreadContextByOsIDLocked(os_id));
>> - if (!context) return false;
>> - *stack_begin = context->stack_begin();
>> - *stack_end = context->stack_end();
>> - *tls_begin = context->tls_begin();
>> - *tls_end = context->tls_end();
>> - *cache_begin = context->cache_begin();
>> - *cache_end = context->cache_end();
>> - *dtls = context->dtls();
>> - return true;
>> -}
>> -
>> void ForEachExtraStackRange(tid_t os_id, RangeIteratorCallback
>> callback,
>> - void *arg) {
>> -}
>> + void *arg) {}
>>
>> -void LockThreadRegistry() {
>> - thread_registry->Lock();
>> -}
>> +void LockThreadRegistry() { thread_registry->Lock(); }
>>
>> -void UnlockThreadRegistry() {
>> - thread_registry->Unlock();
>> -}
>> +void UnlockThreadRegistry() { thread_registry->Unlock(); }
>>
>> ThreadRegistry *GetThreadRegistryLocked() {
>> thread_registry->CheckLocked();
>> return thread_registry;
>> }
>>
>> -} // namespace __lsan
>> +} // namespace __lsan
>> diff --git a/libsanitizer/lsan/lsan_thread.h
>> b/libsanitizer/lsan/lsan_thread.h
>> index b869d066d9d..0ab1582de66 100644
>> --- a/libsanitizer/lsan/lsan_thread.h
>> +++ b/libsanitizer/lsan/lsan_thread.h
>> @@ -16,38 +16,36 @@
>>
>> #include "sanitizer_common/sanitizer_thread_registry.h"
>>
>> -namespace __sanitizer {
>> -struct DTLS;
>> -}
>> -
>> namespace __lsan {
>>
>> -class ThreadContext : public ThreadContextBase {
>> +class ThreadContextLsanBase : public ThreadContextBase {
>> public:
>> - explicit ThreadContext(int tid);
>> - void OnStarted(void *arg) override;
>> + explicit ThreadContextLsanBase(int tid);
>> void OnFinished() override;
>> uptr stack_begin() { return stack_begin_; }
>> uptr stack_end() { return stack_end_; }
>> - uptr tls_begin() { return tls_begin_; }
>> - uptr tls_end() { return tls_end_; }
>> uptr cache_begin() { return cache_begin_; }
>> uptr cache_end() { return cache_end_; }
>> - DTLS *dtls() { return dtls_; }
>>
>> - private:
>> - uptr stack_begin_, stack_end_,
>> - cache_begin_, cache_end_,
>> - tls_begin_, tls_end_;
>> - DTLS *dtls_;
>> + // The argument is passed on to the subclass's OnStarted member
>> function.
>> + static void ThreadStart(u32 tid, tid_t os_id, ThreadType thread_type,
>> + void *onstarted_arg);
>> +
>> + protected:
>> + uptr stack_begin_ = 0;
>> + uptr stack_end_ = 0;
>> + uptr cache_begin_ = 0;
>> + uptr cache_end_ = 0;
>> };
>>
>> +// This subclass of ThreadContextLsanBase is declared in an
>> OS-specific header.
>> +class ThreadContext;
>> +
>> void InitializeThreadRegistry();
>> +void InitializeMainThread();
>>
>> -void ThreadStart(u32 tid, tid_t os_id,
>> - ThreadType thread_type = ThreadType::Regular);
>> +u32 ThreadCreate(u32 tid, uptr uid, bool detached, void *arg =
>> nullptr);
>> void ThreadFinish();
>> -u32 ThreadCreate(u32 tid, uptr uid, bool detached);
>> void ThreadJoin(u32 tid);
>> u32 ThreadTid(uptr uid);
>>
>> @@ -55,6 +53,7 @@ u32 GetCurrentThread();
>> void SetCurrentThread(u32 tid);
>> ThreadContext *CurrentThreadContext();
>> void EnsureMainThreadIDIsCorrect();
>> +
>> } // namespace __lsan
>>
>> #endif // LSAN_THREAD_H
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator.cpp
>> b/libsanitizer/sanitizer_common/sanitizer_allocator.cpp
>> index 8d07906cca0..ec77b9cbfee 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_allocator.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_allocator.cpp
>> @@ -25,7 +25,7 @@ const char *PrimaryAllocatorName =
>> "SizeClassAllocator";
>> const char *SecondaryAllocatorName = "LargeMmapAllocator";
>>
>> // ThreadSanitizer for Go uses libc malloc/free.
>> -#if SANITIZER_GO || defined(SANITIZER_USE_MALLOC)
>> +#if defined(SANITIZER_USE_MALLOC)
>> # if SANITIZER_LINUX && !SANITIZER_ANDROID
>> extern "C" void *__libc_malloc(uptr size);
>> # if !SANITIZER_GO
>> @@ -213,7 +213,7 @@ void *LowLevelAllocator::Allocate(uptr size) {
>> // Align allocation size.
>> size = RoundUpTo(size, low_level_alloc_min_alignment);
>> if (allocated_end_ - allocated_current_ < (sptr)size) {
>> - uptr size_to_allocate = Max(size, GetPageSizeCached());
>> + uptr size_to_allocate = RoundUpTo(size, GetPageSizeCached());
>> allocated_current_ =
>> (char*)MmapOrDie(size_to_allocate, __func__);
>> allocated_end_ = allocated_current_ + size_to_allocate;
>> diff --git
>> a/libsanitizer/sanitizer_common/sanitizer_allocator_primary64.h
>> b/libsanitizer/sanitizer_common/sanitizer_allocator_primary64.h
>> index 90603280e7c..1d9a29c70f3 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_allocator_primary64.h
>> +++ b/libsanitizer/sanitizer_common/sanitizer_allocator_primary64.h
>> @@ -72,11 +72,15 @@ class SizeClassAllocator64 {
>> void Init(s32 release_to_os_interval_ms) {
>> uptr TotalSpaceSize = kSpaceSize + AdditionalSize();
>> if (kUsingConstantSpaceBeg) {
>> + CHECK(IsAligned(kSpaceBeg, SizeClassMap::kMaxSize));
>> CHECK_EQ(kSpaceBeg, address_range.Init(TotalSpaceSize,
>> PrimaryAllocatorName, kSpaceBeg));
>> } else {
>> - NonConstSpaceBeg = address_range.Init(TotalSpaceSize,
>> - PrimaryAllocatorName);
>> + // Combined allocator expects that an 2^N allocation is always
>> aligned to
>> + // 2^N. For this to work, the start of the space needs to be
>> aligned as
>> + // high as the largest size class (which also needs to be a
>> power of 2).
>> + NonConstSpaceBeg = address_range.InitAligned(
>> + TotalSpaceSize, SizeClassMap::kMaxSize,
>> PrimaryAllocatorName);
>> CHECK_NE(NonConstSpaceBeg, ~(uptr)0);
>> }
>> SetReleaseToOSIntervalMs(release_to_os_interval_ms);
>> @@ -220,7 +224,7 @@ class SizeClassAllocator64 {
>>
>> // Test-only.
>> void TestOnlyUnmap() {
>> - UnmapWithCallbackOrDie(SpaceBeg(), kSpaceSize + AdditionalSize());
>> + UnmapWithCallbackOrDie((uptr)address_range.base(),
>> address_range.size());
>> }
>>
>> static void FillMemoryProfile(uptr start, uptr rss, bool file,
>> uptr *stats,
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_common.cpp
>> b/libsanitizer/sanitizer_common/sanitizer_common.cpp
>> index f5f9f49d8cf..87efda5bd37 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_common.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_common.cpp
>> @@ -274,6 +274,7 @@ uptr ReadBinaryNameCached(/*out*/char *buf, uptr
>> buf_len) {
>> return name_len;
>> }
>>
>> +#if !SANITIZER_GO
>> void PrintCmdline() {
>> char **argv = GetArgv();
>> if (!argv) return;
>> @@ -282,6 +283,7 @@ void PrintCmdline() {
>> Printf("%s ", argv[i]);
>> Printf("\n\n");
>> }
>> +#endif
>>
>> // Malloc hooks.
>> static const int kMaxMallocFreeHooks = 5;
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_common.h
>> b/libsanitizer/sanitizer_common/sanitizer_common.h
>> index 87b8f02b5b7..ac16e0e47ef 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_common.h
>> +++ b/libsanitizer/sanitizer_common/sanitizer_common.h
>> @@ -143,6 +143,7 @@ void RunFreeHooks(const void *ptr);
>> class ReservedAddressRange {
>> public:
>> uptr Init(uptr size, const char *name = nullptr, uptr fixed_addr
>> = 0);
>> + uptr InitAligned(uptr size, uptr align, const char *name = nullptr);
>> uptr Map(uptr fixed_addr, uptr size, const char *name = nullptr);
>> uptr MapOrDie(uptr fixed_addr, uptr size, const char *name =
>> nullptr);
>> void Unmap(uptr addr, uptr size);
>> @@ -552,7 +553,7 @@ bool operator!=(const InternalMmapVectorNoCtor<T>
>> &lhs,
>> template<typename T>
>> class InternalMmapVector : public InternalMmapVectorNoCtor<T> {
>> public:
>> - InternalMmapVector() { InternalMmapVectorNoCtor<T>::Initialize(1); }
>> + InternalMmapVector() { InternalMmapVectorNoCtor<T>::Initialize(0); }
>> explicit InternalMmapVector(uptr cnt) {
>> InternalMmapVectorNoCtor<T>::Initialize(cnt);
>> this->resize(cnt);
>> @@ -855,7 +856,7 @@ INLINE uptr GetPthreadDestructorIterations() {
>> #endif
>> }
>>
>> -void *internal_start_thread(void(*func)(void*), void *arg);
>> +void *internal_start_thread(void *(*func)(void*), void *arg);
>> void internal_join_thread(void *th);
>> void MaybeStartBackgroudThread();
>>
>> diff --git
>> a/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc
>> b/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc
>> index 50e3558b52e..57f8b2d2944 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc
>> +++ b/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc
>> @@ -79,13 +79,15 @@
>> #define devname __devname50
>> #define fgetpos __fgetpos50
>> #define fsetpos __fsetpos50
>> +#define fstatvfs __fstatvfs90
>> +#define fstatvfs1 __fstatvfs190
>> #define fts_children __fts_children60
>> #define fts_close __fts_close60
>> #define fts_open __fts_open60
>> #define fts_read __fts_read60
>> #define fts_set __fts_set60
>> #define getitimer __getitimer50
>> -#define getmntinfo __getmntinfo13
>> +#define getmntinfo __getmntinfo90
>> #define getpwent __getpwent50
>> #define getpwnam __getpwnam50
>> #define getpwnam_r __getpwnam_r50
>> @@ -95,6 +97,7 @@
>> #define getutxent __getutxent50
>> #define getutxid __getutxid50
>> #define getutxline __getutxline50
>> +#define getvfsstat __getvfsstat90
>> #define pututxline __pututxline50
>> #define glob __glob30
>> #define gmtime __gmtime50
>> @@ -110,12 +113,15 @@
>> #define setitimer __setitimer50
>> #define setlocale __setlocale50
>> #define shmctl __shmctl50
>> +#define sigaltstack __sigaltstack14
>> #define sigemptyset __sigemptyset14
>> #define sigfillset __sigfillset14
>> #define sigpending __sigpending14
>> #define sigprocmask __sigprocmask14
>> #define sigtimedwait __sigtimedwait50
>> #define stat __stat50
>> +#define statvfs __statvfs90
>> +#define statvfs1 __statvfs190
>> #define time __time50
>> #define times __times13
>> #define unvis __unvis50
>> @@ -128,11 +134,7 @@ extern const short *_tolower_tab_;
>>
>> // Platform-specific options.
>> #if SANITIZER_MAC
>> -namespace __sanitizer {
>> -bool PlatformHasDifferentMemcpyAndMemmove();
>> -}
>> -#define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE \
>> - (__sanitizer::PlatformHasDifferentMemcpyAndMemmove())
>> +#define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE false
>> #elif SANITIZER_WINDOWS64
>> #define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE false
>> #else
>> @@ -4177,11 +4179,27 @@ INTERCEPTOR(int, pthread_mutex_unlock, void
>> *m) {
>>
>> #if SANITIZER_INTERCEPT___PTHREAD_MUTEX
>> INTERCEPTOR(int, __pthread_mutex_lock, void *m) {
>> - return WRAP(pthread_mutex_lock)(m);
>> + void *ctx;
>> + COMMON_INTERCEPTOR_ENTER(ctx, __pthread_mutex_lock, m);
>> + COMMON_INTERCEPTOR_MUTEX_PRE_LOCK(ctx, 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_POST_LOCK(ctx, m);
>> + if (res == errno_EINVAL)
>> + COMMON_INTERCEPTOR_MUTEX_INVALID(ctx, m);
>> + return res;
>> }
>>
>> INTERCEPTOR(int, __pthread_mutex_unlock, void *m) {
>> - return WRAP(pthread_mutex_unlock)(m);
>> + void *ctx;
>> + COMMON_INTERCEPTOR_ENTER(ctx, __pthread_mutex_unlock, m);
>> + COMMON_INTERCEPTOR_MUTEX_UNLOCK(ctx, m);
>> + int res = REAL(__pthread_mutex_unlock)(m);
>> + if (res == errno_EINVAL)
>> + COMMON_INTERCEPTOR_MUTEX_INVALID(ctx, m);
>> + return res;
>> }
>>
>> #define INIT___PTHREAD_MUTEX_LOCK \
>> @@ -6411,12 +6429,11 @@ INTERCEPTOR(SSIZE_T, recvfrom, int fd, void
>> *buf, SIZE_T len, int flags,
>> if (srcaddr) srcaddr_sz = *addrlen;
>> (void)srcaddr_sz; // prevent "set but not used" warning
>> SSIZE_T res = REAL(recvfrom)(fd, buf, len, flags, srcaddr, addrlen);
>> - if (res > 0) {
>> + if (res > 0)
>> COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, Min((SIZE_T)res, len));
>> - if (srcaddr)
>> - COMMON_INTERCEPTOR_INITIALIZE_RANGE(srcaddr,
>> - Min((SIZE_T)*addrlen,
>> srcaddr_sz));
>> - }
>> + if (res >= 0 && srcaddr)
>> + COMMON_INTERCEPTOR_INITIALIZE_RANGE(srcaddr,
>> + Min((SIZE_T)*addrlen,
>> srcaddr_sz));
>> return res;
>> }
>> #define INIT_RECV_RECVFROM \
>> @@ -9623,6 +9640,148 @@ INTERCEPTOR(int, getentropy, void *buf,
>> SIZE_T buflen) {
>> #define INIT_GETENTROPY
>> #endif
>>
>> +#if SANITIZER_INTERCEPT_QSORT
>> +// Glibc qsort uses a temporary buffer allocated either on stack or
>> on heap.
>> +// Poisoned memory from there may get copied into the comparator
>> arguments,
>> +// where it needs to be dealt with. But even that is not enough -
>> the results of
>> +// the sort may be copied into the input/output array based on the
>> results of
>> +// the comparator calls, but directly from the temp memory,
>> bypassing the
>> +// unpoisoning done in wrapped_qsort_compar. We deal with this by,
>> again,
>> +// unpoisoning the entire array after the sort is done.
>> +//
>> +// We can not check that the entire array is initialized at the
>> beginning. IMHO,
>> +// it's fine for parts of the sorted objects to contain
>> uninitialized memory,
>> +// ex. as padding in structs.
>> +typedef int (*qsort_compar_f)(const void *, const void *);
>> +static THREADLOCAL qsort_compar_f qsort_compar;
>> +static THREADLOCAL SIZE_T qsort_size;
>> +int wrapped_qsort_compar(const void *a, const void *b) {
>> + COMMON_INTERCEPTOR_UNPOISON_PARAM(2);
>> + COMMON_INTERCEPTOR_INITIALIZE_RANGE(a, qsort_size);
>> + COMMON_INTERCEPTOR_INITIALIZE_RANGE(b, qsort_size);
>> + return qsort_compar(a, b);
>> +}
>> +
>> +INTERCEPTOR(void, qsort, void *base, SIZE_T nmemb, SIZE_T size,
>> + qsort_compar_f compar) {
>> + void *ctx;
>> + COMMON_INTERCEPTOR_ENTER(ctx, qsort, base, nmemb, size, compar);
>> + // Run the comparator over all array elements to detect any memory
>> issues.
>> + if (nmemb > 1) {
>> + for (SIZE_T i = 0; i < nmemb - 1; ++i) {
>> + void *p = (void *)((char *)base + i * size);
>> + void *q = (void *)((char *)base + (i + 1) * size);
>> + COMMON_INTERCEPTOR_UNPOISON_PARAM(2);
>> + compar(p, q);
>> + }
>> + }
>> + qsort_compar_f old_compar = qsort_compar;
>> + qsort_compar = compar;
>> + SIZE_T old_size = qsort_size;
>> + qsort_size = size;
>> + REAL(qsort)(base, nmemb, size, wrapped_qsort_compar);
>> + qsort_compar = old_compar;
>> + qsort_size = old_size;
>> + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, base, nmemb * size);
>> +}
>> +#define INIT_QSORT COMMON_INTERCEPT_FUNCTION(qsort)
>> +#else
>> +#define INIT_QSORT
>> +#endif
>> +
>> +#if SANITIZER_INTERCEPT_QSORT_R
>> +typedef int (*qsort_r_compar_f)(const void *, const void *, void *);
>> +static THREADLOCAL qsort_r_compar_f qsort_r_compar;
>> +static THREADLOCAL SIZE_T qsort_r_size;
>> +int wrapped_qsort_r_compar(const void *a, const void *b, void *arg) {
>> + COMMON_INTERCEPTOR_UNPOISON_PARAM(3);
>> + COMMON_INTERCEPTOR_INITIALIZE_RANGE(a, qsort_r_size);
>> + COMMON_INTERCEPTOR_INITIALIZE_RANGE(b, qsort_r_size);
>> + return qsort_r_compar(a, b, arg);
>> +}
>> +
>> +INTERCEPTOR(void, qsort_r, void *base, SIZE_T nmemb, SIZE_T size,
>> + qsort_r_compar_f compar, void *arg) {
>> + void *ctx;
>> + COMMON_INTERCEPTOR_ENTER(ctx, qsort_r, base, nmemb, size, compar,
>> arg);
>> + // Run the comparator over all array elements to detect any memory
>> issues.
>> + if (nmemb > 1) {
>> + for (SIZE_T i = 0; i < nmemb - 1; ++i) {
>> + void *p = (void *)((char *)base + i * size);
>> + void *q = (void *)((char *)base + (i + 1) * size);
>> + COMMON_INTERCEPTOR_UNPOISON_PARAM(3);
>> + compar(p, q, arg);
>> + }
>> + }
>> + qsort_r_compar_f old_compar = qsort_r_compar;
>> + qsort_r_compar = compar;
>> + SIZE_T old_size = qsort_r_size;
>> + qsort_r_size = size;
>> + REAL(qsort_r)(base, nmemb, size, wrapped_qsort_r_compar, arg);
>> + qsort_r_compar = old_compar;
>> + qsort_r_size = old_size;
>> + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, base, nmemb * size);
>> +}
>> +#define INIT_QSORT_R COMMON_INTERCEPT_FUNCTION(qsort_r)
>> +#else
>> +#define INIT_QSORT_R
>> +#endif
>> +
>> +#if SANITIZER_INTERCEPT_SIGALTSTACK
>> +INTERCEPTOR(int, sigaltstack, void *ss, void *oss) {
>> + void *ctx;
>> + COMMON_INTERCEPTOR_ENTER(ctx, sigaltstack, ss, oss);
>> + int r = REAL(sigaltstack)(ss, oss);
>> + if (r == 0 && oss != nullptr) {
>> + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oss, struct_stack_t_sz);
>> + }
>> + return r;
>> +}
>> +#define INIT_SIGALTSTACK COMMON_INTERCEPT_FUNCTION(sigaltstack)
>> +#else
>> +#define INIT_SIGALTSTACK
>> +#endif
>> +
>> +#if SANITIZER_INTERCEPT_UNAME
>> +INTERCEPTOR(int, uname, struct utsname *utsname) {
>> +#if SANITIZER_LINUX
>> + if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED)
>> + return internal_uname(utsname);
>> +#endif
>> + void *ctx;
>> + COMMON_INTERCEPTOR_ENTER(ctx, uname, utsname);
>> + int res = REAL(uname)(utsname);
>> + if (!res)
>> + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, utsname,
>> + __sanitizer::struct_utsname_sz);
>> + return res;
>> +}
>> +#define INIT_UNAME COMMON_INTERCEPT_FUNCTION(uname)
>> +#else
>> +#define INIT_UNAME
>> +#endif
>> +
>> +#if SANITIZER_INTERCEPT___XUNAME
>> +// FreeBSD's <sys/utsname.h> define uname() as
>> +// static __inline int uname(struct utsname *name) {
>> +// return __xuname(SYS_NMLN, (void*)name);
>> +// }
>> +INTERCEPTOR(int, __xuname, int size, void *utsname) {
>> + void *ctx;
>> + COMMON_INTERCEPTOR_ENTER(ctx, __xuname, size, utsname);
>> + int res = REAL(__xuname)(size, utsname);
>> + if (!res)
>> + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, utsname,
>> + __sanitizer::struct_utsname_sz);
>> + return res;
>> +}
>> +#define INIT___XUNAME COMMON_INTERCEPT_FUNCTION(__xuname)
>> +#else
>> +#define INIT___XUNAME
>> +#endif
>> +
>> +#include "sanitizer_common_interceptors_netbsd_compat.inc"
>> +
>> static void InitializeCommonInterceptors() {
>> #if SI_POSIX
>> static u64 metadata_mem[sizeof(MetadataHashMap) / sizeof(u64) + 1];
>> @@ -9924,6 +10083,11 @@ static void InitializeCommonInterceptors() {
>> INIT_CRYPT;
>> INIT_CRYPT_R;
>> INIT_GETENTROPY;
>> + INIT_QSORT;
>> + INIT_QSORT_R;
>> + INIT_SIGALTSTACK;
>> + INIT_UNAME;
>> + INIT___XUNAME;
>>
>> INIT___PRINTF_CHK;
>> }
>> diff --git
>> a/libsanitizer/sanitizer_common/sanitizer_common_interceptors_netbsd_compat.inc
>> b/libsanitizer/sanitizer_common/sanitizer_common_interceptors_netbsd_compat.inc
>>
>> new file mode 100644
>> index 00000000000..6aa73ec8c6a
>> --- /dev/null
>> +++
>> b/libsanitizer/sanitizer_common/sanitizer_common_interceptors_netbsd_compat.inc
>> @@ -0,0 +1,128 @@
>> +//===-- sanitizer_common_interceptors_netbsd_compat.inc ---------*-
>> C++ -*-===//
>> +//
>> +// Part of the LLVM Project, under the Apache License v2.0 with LLVM
>> Exceptions.
>> +// See https://llvm.org/LICENSE.txt for license information.
>> +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
>> +//
>> +//===----------------------------------------------------------------------===//
>>
>> +//
>> +// Common function interceptors for tools like AddressSanitizer,
>> +// ThreadSanitizer, MemorySanitizer, etc.
>> +//
>> +// Interceptors for NetBSD old function calls that have been versioned.
>> +//
>> +// NetBSD minimal version supported 9.0.
>> +// NetBSD current version supported 9.99.26.
>> +//
>> +//===----------------------------------------------------------------------===//
>>
>> +
>> +#if SANITIZER_NETBSD
>> +
>> +// First undef all mangled symbols.
>> +// Next, define compat interceptors.
>> +// Finally, undef INIT_ and redefine it.
>> +// This allows to avoid preprocessor issues.
>> +
>> +#undef fstatvfs
>> +#undef fstatvfs1
>> +#undef getmntinfo
>> +#undef getvfsstat
>> +#undef statvfs
>> +#undef statvfs1
>> +
>> +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);
>> + // FIXME: under ASan the call below may write to freed memory and
>> corrupt
>> + // its metadata. See
>> + // https://github.com/google/sanitizers/issues/321.
>> + int res = REAL(statvfs)(path, buf);
>> + if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf,
>> struct_statvfs90_sz);
>> + return res;
>> +}
>> +
>> +INTERCEPTOR(int, fstatvfs, int fd, void *buf) {
>> + void *ctx;
>> + COMMON_INTERCEPTOR_ENTER(ctx, fstatvfs, fd, buf);
>> + COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
>> + // FIXME: under ASan the call below may write to freed memory and
>> corrupt
>> + // its metadata. See
>> + // https://github.com/google/sanitizers/issues/321.
>> + int res = REAL(fstatvfs)(fd, buf);
>> + if (!res) {
>> + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs90_sz);
>> + if (fd >= 0)
>> + COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
>> + }
>> + return res;
>> +}
>> +
>> +#undef INIT_STATVFS
>> +#define INIT_STATVFS \
>> + COMMON_INTERCEPT_FUNCTION(statvfs); \
>> + COMMON_INTERCEPT_FUNCTION(fstatvfs); \
>> + COMMON_INTERCEPT_FUNCTION(__statvfs90); \
>> + COMMON_INTERCEPT_FUNCTION(__fstatvfs90)
>> +
>> +INTERCEPTOR(int, __getmntinfo13, void **mntbufp, int flags) {
>> + void *ctx;
>> + COMMON_INTERCEPTOR_ENTER(ctx, __getmntinfo13, mntbufp, flags);
>> + int cnt = REAL(__getmntinfo13)(mntbufp, flags);
>> + if (cnt > 0 && mntbufp) {
>> + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mntbufp, sizeof(void *));
>> + if (*mntbufp)
>> + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *mntbufp, cnt *
>> struct_statvfs90_sz);
>> + }
>> + return cnt;
>> +}
>> +
>> +#undef INIT_GETMNTINFO
>> +#define INIT_GETMNTINFO \
>> + COMMON_INTERCEPT_FUNCTION(__getmntinfo13); \
>> + COMMON_INTERCEPT_FUNCTION(__getmntinfo90)
>> +
>> +INTERCEPTOR(int, getvfsstat, void *buf, SIZE_T bufsize, int flags) {
>> + void *ctx;
>> + COMMON_INTERCEPTOR_ENTER(ctx, getvfsstat, buf, bufsize, flags);
>> + int ret = REAL(getvfsstat)(buf, bufsize, flags);
>> + if (buf && ret > 0)
>> + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, ret *
>> struct_statvfs90_sz);
>> + return ret;
>> +}
>> +
>> +#undef INIT_GETVFSSTAT
>> +#define INIT_GETVFSSTAT \
>> + COMMON_INTERCEPT_FUNCTION(getvfsstat); \
>> + COMMON_INTERCEPT_FUNCTION(__getvfsstat90)
>> +
>> +INTERCEPTOR(int, statvfs1, const char *path, void *buf, int flags) {
>> + void *ctx;
>> + COMMON_INTERCEPTOR_ENTER(ctx, statvfs1, path, buf, flags);
>> + if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path,
>> REAL(strlen)(path) + 1);
>> + int res = REAL(statvfs1)(path, buf, flags);
>> + if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf,
>> struct_statvfs90_sz);
>> + return res;
>> +}
>> +
>> +INTERCEPTOR(int, fstatvfs1, int fd, void *buf, int flags) {
>> + void *ctx;
>> + COMMON_INTERCEPTOR_ENTER(ctx, fstatvfs1, fd, buf, flags);
>> + COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
>> + int res = REAL(fstatvfs1)(fd, buf, flags);
>> + if (!res) {
>> + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs90_sz);
>> + if (fd >= 0)
>> + COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
>> + }
>> + return res;
>> +}
>> +
>> +#undef INIT_STATVFS1
>> +#define INIT_STATVFS1 \
>> + COMMON_INTERCEPT_FUNCTION(statvfs1); \
>> + COMMON_INTERCEPT_FUNCTION(fstatvfs1); \
>> + COMMON_INTERCEPT_FUNCTION(__statvfs190); \
>> + COMMON_INTERCEPT_FUNCTION(__fstatvfs190)
>> +
>> +#endif
>> diff --git
>> a/libsanitizer/sanitizer_common/sanitizer_common_libcdep.cpp
>> b/libsanitizer/sanitizer_common/sanitizer_common_libcdep.cpp
>> index 27d6a177760..0c918ebb4a9 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_common_libcdep.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_common_libcdep.cpp
>> @@ -30,7 +30,7 @@ SANITIZER_WEAK_ATTRIBUTE StackDepotStats
>> *StackDepotGetStats() {
>> return nullptr;
>> }
>>
>> -void BackgroundThread(void *arg) {
>> +void *BackgroundThread(void *arg) {
>> const uptr hard_rss_limit_mb = common_flags()->hard_rss_limit_mb;
>> const uptr soft_rss_limit_mb = common_flags()->soft_rss_limit_mb;
>> const bool heap_profile = common_flags()->heap_profile;
>> @@ -129,6 +129,16 @@ void SetSandboxingCallback(void (*f)()) {
>> sandboxing_callback = f;
>> }
>>
>> +uptr ReservedAddressRange::InitAligned(uptr size, uptr align,
>> + const char *name) {
>> + CHECK(IsPowerOfTwo(align));
>> + if (align <= GetPageSizeCached())
>> + return Init(size, name);
>> + uptr start = Init(size + align, name);
>> + start += align - (start & (align - 1));
>> + return start;
>> +}
>> +
>> } // namespace __sanitizer
>>
>> SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_sandbox_on_notify,
>> diff --git
>> a/libsanitizer/sanitizer_common/sanitizer_common_syscalls.inc
>> b/libsanitizer/sanitizer_common/sanitizer_common_syscalls.inc
>> index 31ff48cfd2c..532ac9ead34 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_common_syscalls.inc
>> +++ b/libsanitizer/sanitizer_common/sanitizer_common_syscalls.inc
>> @@ -2885,6 +2885,23 @@ POST_SYSCALL(getrandom)(long res, void *buf,
>> uptr count, long flags) {
>> POST_WRITE(buf, res);
>> }
>> }
>> +
>> +PRE_SYSCALL(sigaltstack)(const void *ss, void *oss) {
>> + if (ss != nullptr) {
>> + PRE_READ(ss, struct_stack_t_sz);
>> + }
>> + if (oss != nullptr) {
>> + PRE_WRITE(oss, struct_stack_t_sz);
>> + }
>> +}
>> +
>> +POST_SYSCALL(sigaltstack)(long res, void *ss, void *oss) {
>> + if (res == 0) {
>> + if (oss != nullptr) {
>> + POST_WRITE(oss, struct_stack_t_sz);
>> + }
>> + }
>> +}
>> } // extern "C"
>>
>> #undef PRE_SYSCALL
>> diff --git
>> a/libsanitizer/sanitizer_common/sanitizer_coverage_fuchsia.cpp
>> b/libsanitizer/sanitizer_common/sanitizer_coverage_fuchsia.cpp
>> index f18cee66b84..a52db08433e 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_coverage_fuchsia.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_coverage_fuchsia.cpp
>> @@ -27,15 +27,15 @@
>>
>> #include "sanitizer_platform.h"
>> #if SANITIZER_FUCHSIA
>> +#include <zircon/process.h>
>> +#include <zircon/sanitizer.h>
>> +#include <zircon/syscalls.h>
>> +
>> #include "sanitizer_atomic.h"
>> #include "sanitizer_common.h"
>> #include "sanitizer_internal_defs.h"
>> #include "sanitizer_symbolizer_fuchsia.h"
>>
>> -#include <zircon/process.h>
>> -#include <zircon/sanitizer.h>
>> -#include <zircon/syscalls.h>
>> -
>> using namespace __sanitizer;
>>
>> namespace __sancov {
>> @@ -82,7 +82,8 @@ class TracePcGuardController final {
>> void TracePcGuard(u32 *guard, uptr pc) {
>> atomic_uint32_t *guard_ptr = reinterpret_cast<atomic_uint32_t
>> *>(guard);
>> u32 idx = atomic_exchange(guard_ptr, 0, memory_order_relaxed);
>> - if (idx > 0) array_[idx] = pc;
>> + if (idx > 0)
>> + array_[idx] = pc;
>> }
>>
>> void Dump() {
>> @@ -140,6 +141,10 @@ class TracePcGuardController final {
>> internal_getpid());
>> _zx_object_set_property(vmo_, ZX_PROP_NAME, vmo_name_,
>> internal_strlen(vmo_name_));
>> + uint64_t size = DataSize();
>> + status = _zx_object_set_property(vmo_,
>> ZX_PROP_VMO_CONTENT_SIZE, &size,
>> + sizeof(size));
>> + CHECK_EQ(status, ZX_OK);
>>
>> // Map the largest possible view we might need into the VMO.
>> Later
>> // we might need to increase the VMO's size before we can use
>> larger
>> @@ -172,6 +177,10 @@ class TracePcGuardController final {
>>
>> zx_status_t status = _zx_vmo_set_size(vmo_, DataSize());
>> CHECK_EQ(status, ZX_OK);
>> + uint64_t size = DataSize();
>> + status = _zx_object_set_property(vmo_,
>> ZX_PROP_VMO_CONTENT_SIZE, &size,
>> + sizeof(size));
>> + CHECK_EQ(status, ZX_OK);
>>
>> return first_index;
>> }
>> @@ -204,13 +213,15 @@ SANITIZER_INTERFACE_ATTRIBUTE void
>> __sanitizer_dump_coverage(const uptr *pcs,
>> }
>>
>> SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard,
>> u32 *guard) {
>> - if (!*guard) return;
>> + if (!*guard)
>> + return;
>> __sancov::pc_guard_controller.TracePcGuard(guard, GET_CALLER_PC()
>> - 1);
>> }
>>
>> SANITIZER_INTERFACE_WEAK_DEF(void,
>> __sanitizer_cov_trace_pc_guard_init,
>> u32 *start, u32 *end) {
>> - if (start == end || *start) return;
>> + if (start == end || *start)
>> + return;
>> __sancov::pc_guard_controller.InitTracePcGuard(start, end);
>> }
>>
>> diff --git
>> a/libsanitizer/sanitizer_common/sanitizer_coverage_interface.inc
>> b/libsanitizer/sanitizer_common/sanitizer_coverage_interface.inc
>> index 7beeff7e8af..d7ab0c3d98c 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_coverage_interface.inc
>> +++ b/libsanitizer/sanitizer_common/sanitizer_coverage_interface.inc
>> @@ -29,4 +29,5 @@
>> INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_pc_guard_init)
>> INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_pc_indir)
>> INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_switch)
>> INTERFACE_WEAK_FUNCTION(__sanitizer_cov_8bit_counters_init)
>> +INTERFACE_WEAK_FUNCTION(__sanitizer_cov_bool_flag_init)
>> INTERFACE_WEAK_FUNCTION(__sanitizer_cov_pcs_init)
>> diff --git
>> a/libsanitizer/sanitizer_common/sanitizer_coverage_libcdep_new.cpp
>> b/libsanitizer/sanitizer_common/sanitizer_coverage_libcdep_new.cpp
>> index 6a75792f926..73ebeb5fa14 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_coverage_libcdep_new.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_coverage_libcdep_new.cpp
>> @@ -207,6 +207,7 @@ SANITIZER_INTERFACE_WEAK_DEF(void,
>> __sanitizer_cov_trace_div8, void) {}
>> SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_gep, void) {}
>> SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_indir,
>> void) {}
>> SANITIZER_INTERFACE_WEAK_DEF(void,
>> __sanitizer_cov_8bit_counters_init, void) {}
>> +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_bool_flag_init,
>> void) {}
>> SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_pcs_init, void) {}
>> } // extern "C"
>> // Weak definition for code instrumented with
>> -fsanitize-coverage=stack-depth
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_file.h
>> b/libsanitizer/sanitizer_common/sanitizer_file.h
>> index 4a78a0e0ac8..26681f0493d 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_file.h
>> +++ b/libsanitizer/sanitizer_common/sanitizer_file.h
>> @@ -87,8 +87,8 @@ bool IsAbsolutePath(const char *path);
>> // The child process will close all fds after STDERR_FILENO
>> // before passing control to a program.
>> pid_t StartSubprocess(const char *filename, const char *const argv[],
>> - fd_t stdin_fd = kInvalidFd, fd_t stdout_fd =
>> kInvalidFd,
>> - fd_t stderr_fd = kInvalidFd);
>> + const char *const envp[], fd_t stdin_fd =
>> kInvalidFd,
>> + fd_t stdout_fd = kInvalidFd, fd_t stderr_fd =
>> kInvalidFd);
>> // Checks if specified process is still running
>> bool IsProcessRunning(pid_t pid);
>> // Waits for the process to finish and returns its exit code.
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_flag_parser.cpp
>> b/libsanitizer/sanitizer_common/sanitizer_flag_parser.cpp
>> index 1e2bc665261..9e274268bf2 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_flag_parser.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_flag_parser.cpp
>> @@ -56,9 +56,16 @@ char *FlagParser::ll_strndup(const char *s, uptr n) {
>> }
>>
>> void FlagParser::PrintFlagDescriptions() {
>> + char buffer[128];
>> + buffer[sizeof(buffer) - 1] = '\0';
>> Printf("Available flags for %s:\n", SanitizerToolName);
>> - for (int i = 0; i < n_flags_; ++i)
>> - Printf("\t%s\n\t\t- %s\n", flags_[i].name, flags_[i].desc);
>> + for (int i = 0; i < n_flags_; ++i) {
>> + bool truncated = !(flags_[i].handler->Format(buffer,
>> sizeof(buffer)));
>> + CHECK_EQ(buffer[sizeof(buffer) - 1], '\0');
>> + const char *truncation_str = truncated ? " Truncated" : "";
>> + Printf("\t%s\n\t\t- %s (Current Value%s: %s)\n", flags_[i].name,
>> + flags_[i].desc, truncation_str, buffer);
>> + }
>> }
>>
>> void FlagParser::fatal_error(const char *err) {
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_flag_parser.h
>> b/libsanitizer/sanitizer_common/sanitizer_flag_parser.h
>> index c24ad25626b..fac5dff3463 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_flag_parser.h
>> +++ b/libsanitizer/sanitizer_common/sanitizer_flag_parser.h
>> @@ -22,9 +22,23 @@ namespace __sanitizer {
>> class FlagHandlerBase {
>> public:
>> virtual bool Parse(const char *value) { return false; }
>> + // Write the C string representation of the current value
>> (truncated to fit)
>> + // into the buffer of size `size`. Returns false if truncation
>> occurred and
>> + // returns true otherwise.
>> + virtual bool Format(char *buffer, uptr size) {
>> + if (size > 0)
>> + buffer[0] = '\0';
>> + return false;
>> + }
>>
>> protected:
>> ~FlagHandlerBase() {}
>> +
>> + inline bool FormatString(char *buffer, uptr size, const char
>> *str_to_use) {
>> + uptr num_symbols_should_write =
>> + internal_snprintf(buffer, size, "%s", str_to_use);
>> + return num_symbols_should_write < size;
>> + }
>> };
>>
>> template <typename T>
>> @@ -34,6 +48,7 @@ class FlagHandler : public FlagHandlerBase {
>> public:
>> explicit FlagHandler(T *t) : t_(t) {}
>> bool Parse(const char *value) final;
>> + bool Format(char *buffer, uptr size) final;
>> };
>>
>> inline bool ParseBool(const char *value, bool *b) {
>> @@ -59,6 +74,11 @@ inline bool FlagHandler<bool>::Parse(const char
>> *value) {
>> return false;
>> }
>>
>> +template <>
>> +inline bool FlagHandler<bool>::Format(char *buffer, uptr size) {
>> + return FormatString(buffer, size, *t_ ? "true" : "false");
>> +}
>> +
>> template <>
>> inline bool FlagHandler<HandleSignalMode>::Parse(const char *value) {
>> bool b;
>> @@ -75,12 +95,23 @@ inline bool
>> FlagHandler<HandleSignalMode>::Parse(const char *value) {
>> return false;
>> }
>>
>> +template <>
>> +inline bool FlagHandler<HandleSignalMode>::Format(char *buffer, uptr
>> size) {
>> + uptr num_symbols_should_write = internal_snprintf(buffer, size,
>> "%d", *t_);
>> + return num_symbols_should_write < size;
>> +}
>> +
>> template <>
>> inline bool FlagHandler<const char *>::Parse(const char *value) {
>> *t_ = value;
>> return true;
>> }
>>
>> +template <>
>> +inline bool FlagHandler<const char *>::Format(char *buffer, uptr
>> size) {
>> + return FormatString(buffer, size, *t_);
>> +}
>> +
>> template <>
>> inline bool FlagHandler<int>::Parse(const char *value) {
>> const char *value_end;
>> @@ -90,6 +121,12 @@ inline bool FlagHandler<int>::Parse(const char
>> *value) {
>> return ok;
>> }
>>
>> +template <>
>> +inline bool FlagHandler<int>::Format(char *buffer, uptr size) {
>> + uptr num_symbols_should_write = internal_snprintf(buffer, size,
>> "%d", *t_);
>> + return num_symbols_should_write < size;
>> +}
>> +
>> template <>
>> inline bool FlagHandler<uptr>::Parse(const char *value) {
>> const char *value_end;
>> @@ -99,6 +136,12 @@ inline bool FlagHandler<uptr>::Parse(const char
>> *value) {
>> return ok;
>> }
>>
>> +template <>
>> +inline bool FlagHandler<uptr>::Format(char *buffer, uptr size) {
>> + uptr num_symbols_should_write = internal_snprintf(buffer, size,
>> "%p", *t_);
>> + return num_symbols_should_write < size;
>> +}
>> +
>> template <>
>> inline bool FlagHandler<s64>::Parse(const char *value) {
>> const char *value_end;
>> @@ -108,6 +151,12 @@ inline bool FlagHandler<s64>::Parse(const char
>> *value) {
>> return ok;
>> }
>>
>> +template <>
>> +inline bool FlagHandler<s64>::Format(char *buffer, uptr size) {
>> + uptr num_symbols_should_write = internal_snprintf(buffer, size,
>> "%lld", *t_);
>> + return num_symbols_should_write < size;
>> +}
>> +
>> class FlagParser {
>> static const int kMaxFlags = 200;
>> struct Flag {
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_flags.cpp
>> b/libsanitizer/sanitizer_common/sanitizer_flags.cpp
>> index 66a0a5579ed..684ee1e0b99 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_flags.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_flags.cpp
>> @@ -75,11 +75,13 @@ void SubstituteForFlagValue(const char *s, char
>> *out, uptr out_size) {
>> class FlagHandlerInclude : public FlagHandlerBase {
>> FlagParser *parser_;
>> bool ignore_missing_;
>> + const char *original_path_;
>>
>> public:
>> explicit FlagHandlerInclude(FlagParser *parser, bool ignore_missing)
>> - : parser_(parser), ignore_missing_(ignore_missing) {}
>> + : parser_(parser), ignore_missing_(ignore_missing),
>> original_path_("") {}
>> bool Parse(const char *value) final {
>> + original_path_ = value;
>> if (internal_strchr(value, '%')) {
>> char *buf = (char *)MmapOrDie(kMaxPathLength,
>> "FlagHandlerInclude");
>> SubstituteForFlagValue(value, buf, kMaxPathLength);
>> @@ -89,6 +91,12 @@ class FlagHandlerInclude : public FlagHandlerBase {
>> }
>> return parser_->ParseFile(value, ignore_missing_);
>> }
>> + bool Format(char *buffer, uptr size) {
>> + // Note `original_path_` isn't actually what's parsed due to `%`
>> + // substitutions. Printing the substituted path would require
>> holding onto
>> + // mmap'ed memory.
>> + return FormatString(buffer, size, original_path_);
>> + }
>> };
>>
>> void RegisterIncludeFlags(FlagParser *parser, CommonFlags *cf) {
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_freebsd.h
>> b/libsanitizer/sanitizer_common/sanitizer_freebsd.h
>> index 64cb21f1c3d..82b227eab6d 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_freebsd.h
>> +++ b/libsanitizer/sanitizer_common/sanitizer_freebsd.h
>> @@ -19,11 +19,11 @@
>> // x86-64 FreeBSD 9.2 and older define 'ucontext_t' incorrectly in
>> // 32-bit mode.
>> #if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32)
>> -# include <osreldate.h>
>> -# if __FreeBSD_version <= 902001 // v9.2
>> -# include <link.h>
>> -# include <sys/param.h>
>> -# include <ucontext.h>
>> +#include <osreldate.h>
>> +#if __FreeBSD_version <= 902001 // v9.2
>> +#include <link.h>
>> +#include <sys/param.h>
>> +#include <ucontext.h>
>>
>> namespace __sanitizer {
>>
>> @@ -68,8 +68,8 @@ typedef struct __xmcontext {
>> } xmcontext_t;
>>
>> typedef struct __xucontext {
>> - sigset_t uc_sigmask;
>> - xmcontext_t uc_mcontext;
>> + sigset_t uc_sigmask;
>> + xmcontext_t uc_mcontext;
>>
>> struct __ucontext *uc_link;
>> stack_t uc_stack;
>> @@ -122,15 +122,16 @@ struct xdl_phdr_info {
>> void *dlpi_tls_data;
>> };
>>
>> -typedef int (*__xdl_iterate_hdr_callback)(struct xdl_phdr_info*,
>> size_t, void*);
>> -typedef int xdl_iterate_phdr_t(__xdl_iterate_hdr_callback, void*);
>> +typedef int (*__xdl_iterate_hdr_callback)(struct xdl_phdr_info *,
>> size_t,
>> + void *);
>> +typedef int xdl_iterate_phdr_t(__xdl_iterate_hdr_callback, void *);
>>
>> #define xdl_iterate_phdr(callback, param) \
>> - (((xdl_iterate_phdr_t*) dl_iterate_phdr)((callback), (param)))
>> + (((xdl_iterate_phdr_t *)dl_iterate_phdr)((callback), (param)))
>>
>> } // namespace __sanitizer
>>
>> -# endif // __FreeBSD_version <= 902001
>> +#endif // __FreeBSD_version <= 902001
>> #endif // SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32)
>>
>> #endif // SANITIZER_FREEBSD_H
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_fuchsia.cpp
>> b/libsanitizer/sanitizer_common/sanitizer_fuchsia.cpp
>> index 6e2c6137f0c..6d1ad794677 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_fuchsia.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_fuchsia.cpp
>> @@ -66,6 +66,10 @@ uptr internal_getpid() {
>> return pid;
>> }
>>
>> +int internal_dlinfo(void *handle, int request, void *p) {
>> + UNIMPLEMENTED();
>> +}
>> +
>> uptr GetThreadSelf() { return
>> reinterpret_cast<uptr>(thrd_current()); }
>>
>> tid_t GetTid() { return GetThreadSelf(); }
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_fuchsia.h
>> b/libsanitizer/sanitizer_common/sanitizer_fuchsia.h
>> index 5a2ad32b411..96f9cde7ef1 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_fuchsia.h
>> +++ b/libsanitizer/sanitizer_common/sanitizer_fuchsia.h
>> @@ -18,12 +18,18 @@
>> #include "sanitizer_common.h"
>>
>> #include <zircon/sanitizer.h>
>> +#include <zircon/syscalls/object.h>
>>
>> namespace __sanitizer {
>>
>> extern uptr MainThreadStackBase, MainThreadStackSize;
>> extern sanitizer_shadow_bounds_t ShadowBounds;
>>
>> +struct MemoryMappingLayoutData {
>> + InternalMmapVector<zx_info_maps_t> data;
>> + size_t current; // Current index into the vector.
>> +};
>> +
>> } // namespace __sanitizer
>>
>> #endif // SANITIZER_FUCHSIA
>> diff --git
>> a/libsanitizer/sanitizer_common/sanitizer_interceptors_ioctl_netbsd.inc
>> b/libsanitizer/sanitizer_common/sanitizer_interceptors_ioctl_netbsd.inc
>> index 03ef7c1788c..576807ea3a6 100644
>> ---
>> a/libsanitizer/sanitizer_common/sanitizer_interceptors_ioctl_netbsd.inc
>> +++
>> b/libsanitizer/sanitizer_common/sanitizer_interceptors_ioctl_netbsd.inc
>> @@ -24,7 +24,7 @@ struct ioctl_desc {
>> const char *name;
>> };
>>
>> -const unsigned ioctl_table_max = 1236;
>> +const unsigned ioctl_table_max = 1238;
>> static ioctl_desc ioctl_table[ioctl_table_max];
>> static unsigned ioctl_table_size = 0;
>>
>> @@ -166,9 +166,6 @@ static void ioctl_table_fill() {
>> _(FE_ENABLE_HIGH_LNB_VOLTAGE, READ, sizeof(int));
>> _(FE_SET_FRONTEND_TUNE_MODE, READ, sizeof(unsigned int));
>> _(FE_DISHNETWORK_SEND_LEGACY_CMD, READ, sizeof(unsigned long));
>> - /* Entries from file: dev/filemon/filemon.h */
>> - _(FILEMON_SET_FD, READWRITE, sizeof(int));
>> - _(FILEMON_SET_PID, READWRITE, sizeof(int));
>> /* Entries from file: dev/hdaudio/hdaudioio.h */
>> _(HDAUDIO_FGRP_INFO, READWRITE, struct_plistref_sz);
>> _(HDAUDIO_FGRP_GETCONFIG, READWRITE, struct_plistref_sz);
>> @@ -449,9 +446,6 @@ static void ioctl_table_fill() {
>> _(STICIO_STOPQ, NONE, 0);
>> /* Entries from file: dev/usb/ukyopon.h */
>> _(UKYOPON_IDENTIFY, WRITE, struct_ukyopon_identify_sz);
>> - /* Entries from file: dev/usb/urio.h */
>> - _(URIO_SEND_COMMAND, READWRITE, struct_urio_command_sz);
>> - _(URIO_RECV_COMMAND, READWRITE, struct_urio_command_sz);
>> /* Entries from file: dev/usb/usb.h */
>> _(USB_REQUEST, READWRITE, struct_usb_ctl_request_sz);
>> _(USB_SETDEBUG, READ, sizeof(int));
>> @@ -653,6 +647,7 @@ static void ioctl_table_fill() {
>> _(NVMM_IOC_MACHINE_CONFIGURE, READ,
>> struct_nvmm_ioc_machine_configure_sz);
>> _(NVMM_IOC_VCPU_CREATE, READ, struct_nvmm_ioc_vcpu_create_sz);
>> _(NVMM_IOC_VCPU_DESTROY, READ, struct_nvmm_ioc_vcpu_destroy_sz);
>> + _(NVMM_IOC_VCPU_CONFIGURE, READ, struct_nvmm_ioc_vcpu_configure_sz);
>> _(NVMM_IOC_VCPU_SETSTATE, READ, struct_nvmm_ioc_vcpu_setstate_sz);
>> _(NVMM_IOC_VCPU_GETSTATE, READ, struct_nvmm_ioc_vcpu_getstate_sz);
>> _(NVMM_IOC_VCPU_INJECT, READ, struct_nvmm_ioc_vcpu_inject_sz);
>> @@ -735,6 +730,7 @@ static void ioctl_table_fill() {
>> _(IOC_NPF_SAVE, WRITE, struct_nvlist_ref_sz);
>> _(IOC_NPF_RULE, READWRITE, struct_nvlist_ref_sz);
>> _(IOC_NPF_CONN_LOOKUP, READWRITE, struct_nvlist_ref_sz);
>> + _(IOC_NPF_TABLE_REPLACE, READWRITE, struct_nvlist_ref_sz);
>> /* Entries from file: net/if_pppoe.h */
>> _(PPPOESETPARMS, READ, struct_pppoediscparms_sz);
>> _(PPPOEGETPARMS, READWRITE, struct_pppoediscparms_sz);
>> @@ -1403,8 +1399,14 @@ static void ioctl_table_fill() {
>> _(SNDCTL_DSP_SETRECVOL, READ, sizeof(unsigned int));
>> _(SNDCTL_DSP_SKIP, NONE, 0);
>> _(SNDCTL_DSP_SILENCE, NONE, 0);
>> + /* Entries from file: dev/filemon/filemon.h (compat <= 9.99.26) */
>> + _(FILEMON_SET_FD, READWRITE, sizeof(int));
>> + _(FILEMON_SET_PID, READWRITE, sizeof(int));
>> + /* Entries from file: dev/usb/urio.h (compat <= 9.99.43) */
>> + _(URIO_SEND_COMMAND, READWRITE, struct_urio_command_sz);
>> + _(URIO_RECV_COMMAND, READWRITE, struct_urio_command_sz);
>> #undef _
>> -} // NOLINT
>> +} // NOLINT
>>
>> static bool ioctl_initialized = false;
>>
>> diff --git
>> a/libsanitizer/sanitizer_common/sanitizer_interface_internal.h
>> b/libsanitizer/sanitizer_common/sanitizer_interface_internal.h
>> index c110eff130f..be8023e9e16 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_interface_internal.h
>> +++ b/libsanitizer/sanitizer_common/sanitizer_interface_internal.h
>> @@ -109,8 +109,10 @@ extern "C" {
>> __sanitizer::u32*);
>> SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
>> void __sanitizer_cov_8bit_counters_init();
>> - SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
>> - void __sanitizer_cov_pcs_init();
>> + SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void
>> + __sanitizer_cov_bool_flag_init();
>> + SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void
>> + __sanitizer_cov_pcs_init();
>> } // extern "C"
>>
>> #endif // SANITIZER_INTERFACE_INTERNAL_H
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_internal_defs.h
>> b/libsanitizer/sanitizer_common/sanitizer_internal_defs.h
>> index 00226305e07..d0ffc79b061 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_internal_defs.h
>> +++ b/libsanitizer/sanitizer_common/sanitizer_internal_defs.h
>> @@ -105,7 +105,7 @@
>> // FIXME: do we have anything like this on Mac?
>> #ifndef SANITIZER_CAN_USE_PREINIT_ARRAY
>> #if ((SANITIZER_LINUX && !SANITIZER_ANDROID) || SANITIZER_OPENBSD || \
>> - SANITIZER_FUCHSIA) && !defined(PIC)
>> + SANITIZER_FUCHSIA || SANITIZER_NETBSD) && !defined(PIC)
>> #define SANITIZER_CAN_USE_PREINIT_ARRAY 1
>> // Before Solaris 11.4, .preinit_array is fully supported only with
>> GNU ld.
>> // FIXME: Check for those conditions.
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_libc.h
>> b/libsanitizer/sanitizer_common/sanitizer_libc.h
>> index 3d5db35d68b..ec0a6ded009 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_libc.h
>> +++ b/libsanitizer/sanitizer_common/sanitizer_libc.h
>> @@ -72,6 +72,8 @@ unsigned int internal_sleep(unsigned int seconds);
>> uptr internal_getpid();
>> uptr internal_getppid();
>>
>> +int internal_dlinfo(void *handle, int request, void *p);
>> +
>> // Threading
>> uptr internal_sched_yield();
>>
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_linux.cpp
>> b/libsanitizer/sanitizer_common/sanitizer_linux.cpp
>> index 3807a79b1cd..2168301fd69 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_linux.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_linux.cpp
>> @@ -26,7 +26,7 @@
>> #include "sanitizer_placement_new.h"
>> #include "sanitizer_procmaps.h"
>>
>> -#if SANITIZER_LINUX
>> +#if SANITIZER_LINUX && !SANITIZER_GO
>> #include <asm/param.h>
>> #endif
>>
>> @@ -166,7 +166,7 @@ namespace __sanitizer {
>> #if !SANITIZER_SOLARIS && !SANITIZER_NETBSD
>> #if !SANITIZER_S390 && !SANITIZER_OPENBSD
>> uptr internal_mmap(void *addr, uptr length, int prot, int flags,
>> int fd,
>> - OFF_T offset) {
>> + u64 offset) {
>> #if SANITIZER_FREEBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS
>> return internal_syscall(SYSCALL(mmap), (uptr)addr, length, prot,
>> flags, fd,
>> offset);
>> @@ -552,13 +552,14 @@ const char *GetEnv(const char *name) {
>> #endif
>> }
>>
>> -#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD && !SANITIZER_OPENBSD
>> +#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD && !SANITIZER_OPENBSD && \
>> + !SANITIZER_GO
>> extern "C" {
>> SANITIZER_WEAK_ATTRIBUTE extern void *__libc_stack_end;
>> }
>> #endif
>>
>> -#if !SANITIZER_GO && !SANITIZER_FREEBSD && !SANITIZER_NETBSD
>> && \
>> +#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD && \
>> !SANITIZER_OPENBSD
>> static void ReadNullSepFileToArray(const char *path, char ***arr,
>> int arr_size) {
>> @@ -604,16 +605,21 @@ static void GetArgsAndEnv(char ***argv, char
>> ***envp) {
>> #else // SANITIZER_FREEBSD
>> #if !SANITIZER_GO
>> if (&__libc_stack_end) {
>> -#endif // !SANITIZER_GO
>> uptr* stack_end = (uptr*)__libc_stack_end;
>> - int argc = *stack_end;
>> + // Normally argc can be obtained from *stack_end, however, on
>> ARM glibc's
>> + // _start clobbers it:
>> + //
>> https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/arm/start.S;hb=refs/heads/release/2.31/master#l75
>> + // Do not special-case ARM and infer argc from argv everywhere.
>> + int argc = 0;
>> + while (stack_end[argc + 1]) argc++;
>> *argv = (char**)(stack_end + 1);
>> *envp = (char**)(stack_end + argc + 2);
>> -#if !SANITIZER_GO
>> } else {
>> +#endif // !SANITIZER_GO
>> static const int kMaxArgv = 2000, kMaxEnvp = 2000;
>> ReadNullSepFileToArray("/proc/self/cmdline", argv, kMaxArgv);
>> ReadNullSepFileToArray("/proc/self/environ", envp, kMaxEnvp);
>> +#if !SANITIZER_GO
>> }
>> #endif // !SANITIZER_GO
>> #endif // SANITIZER_FREEBSD
>> @@ -735,6 +741,14 @@ uptr internal_getppid() {
>> return internal_syscall(SYSCALL(getppid));
>> }
>>
>> +int internal_dlinfo(void *handle, int request, void *p) {
>> +#if SANITIZER_FREEBSD
>> + return dlinfo(handle, request, p);
>> +#else
>> + UNIMPLEMENTED();
>> +#endif
>> +}
>> +
>> uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned
>> int count) {
>> #if SANITIZER_FREEBSD
>> return internal_syscall(SYSCALL(getdirentries), fd, (uptr)dirp,
>> count, NULL);
>> @@ -1006,9 +1020,8 @@ static uptr GetKernelAreaSize() {
>> // is modified (e.g. under schroot) so check this as well.
>> struct utsname uname_info;
>> int pers = personality(0xffffffffUL);
>> - if (!(pers & PER_MASK)
>> - && uname(&uname_info) == 0
>> - && internal_strstr(uname_info.machine, "64"))
>> + if (!(pers & PER_MASK) && internal_uname(&uname_info) == 0 &&
>> + internal_strstr(uname_info.machine, "64"))
>> return 0;
>> #endif // SANITIZER_ANDROID
>>
>> @@ -1063,7 +1076,8 @@ uptr GetMaxUserVirtualAddress() {
>>
>> #if !SANITIZER_ANDROID
>> uptr GetPageSize() {
>> -#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__i386__))
>> +#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__i386__)) && \
>> + defined(EXEC_PAGESIZE)
>> return EXEC_PAGESIZE;
>> #elif SANITIZER_FREEBSD || SANITIZER_NETBSD
>> // Use sysctl as sysconf can trigger interceptors internally.
>> @@ -1619,6 +1633,12 @@ uptr internal_clone(int (*fn)(void *), void
>> *child_stack, int flags, void *arg,
>> }
>> #endif // defined(__x86_64__) && SANITIZER_LINUX
>>
>> +#if SANITIZER_LINUX
>> +int internal_uname(struct utsname *buf) {
>> + return internal_syscall(SYSCALL(uname), buf);
>> +}
>> +#endif
>> +
>> #if SANITIZER_ANDROID
>> #if __ANDROID_API__ < 21
>> extern "C" __attribute__((weak)) int dl_iterate_phdr(
>> @@ -1701,7 +1721,7 @@ HandleSignalMode GetHandleSignalMode(int signum) {
>> }
>>
>> #if !SANITIZER_GO
>> -void *internal_start_thread(void(*func)(void *arg), void *arg) {
>> +void *internal_start_thread(void *(*func)(void *arg), void *arg) {
>> // Start the thread with signals blocked, otherwise it can steal
>> user signals.
>> __sanitizer_sigset_t set, old;
>> internal_sigfillset(&set);
>> @@ -1712,7 +1732,7 @@ void *internal_start_thread(void(*func)(void
>> *arg), void *arg) {
>> #endif
>> internal_sigprocmask(SIG_SETMASK, &set, &old);
>> void *th;
>> - real_pthread_create(&th, nullptr, (void*(*)(void *arg))func, arg);
>> + real_pthread_create(&th, nullptr, func, arg);
>> internal_sigprocmask(SIG_SETMASK, &old, nullptr);
>> return th;
>> }
>> @@ -1721,7 +1741,7 @@ void internal_join_thread(void *th) {
>> real_pthread_join(th, nullptr);
>> }
>> #else
>> -void *internal_start_thread(void (*func)(void *), void *arg) {
>> return 0; }
>> +void *internal_start_thread(void *(*func)(void *), void *arg) {
>> return 0; }
>>
>> void internal_join_thread(void *th) {}
>> #endif
>> @@ -1846,6 +1866,105 @@ SignalContext::WriteFlag
>> SignalContext::GetWriteFlag() const {
>> #endif
>> u32 instr = *(u32 *)pc;
>> return (instr >> 21) & 1 ? WRITE: READ;
>> +#elif defined(__riscv)
>> + unsigned long pc = ucontext->uc_mcontext.__gregs[REG_PC];
>> + unsigned faulty_instruction = *(uint16_t *)pc;
>> +
>> +#if defined(__riscv_compressed)
>> + if ((faulty_instruction & 0x3) != 0x3) { // it's a compressed
>> instruction
>> + // set op_bits to the instruction bits [1, 0, 15, 14, 13]
>> + unsigned op_bits =
>> + ((faulty_instruction & 0x3) << 3) | (faulty_instruction >> 13);
>> + unsigned rd = faulty_instruction & 0xF80; // bits 7-11, inclusive
>> + switch (op_bits) {
>> + case 0b10'010: // c.lwsp (rd != x0)
>> +#if __riscv_xlen == 64
>> + case 0b10'011: // c.ldsp (rd != x0)
>> +#endif
>> + return rd ? SignalContext::READ : SignalContext::UNKNOWN;
>> + case 0b00'010: // c.lw
>> +#if __riscv_flen >= 32 && __riscv_xlen == 32
>> + case 0b10'011: // c.flwsp
>> +#endif
>> +#if __riscv_flen >= 32 || __riscv_xlen == 64
>> + case 0b00'011: // c.flw / c.ld
>> +#endif
>> +#if __riscv_flen == 64
>> + case 0b00'001: // c.fld
>> + case 0b10'001: // c.fldsp
>> +#endif
>> + return SignalContext::READ;
>> + case 0b00'110: // c.sw
>> + case 0b10'110: // c.swsp
>> +#if __riscv_flen >= 32 || __riscv_xlen == 64
>> + case 0b00'111: // c.fsw / c.sd
>> + case 0b10'111: // c.fswsp / c.sdsp
>> +#endif
>> +#if __riscv_flen == 64
>> + case 0b00'101: // c.fsd
>> + case 0b10'101: // c.fsdsp
>> +#endif
>> + return SignalContext::WRITE;
>> + default:
>> + return SignalContext::UNKNOWN;
>> + }
>> + }
>> +#endif
>> +
>> + unsigned opcode = faulty_instruction & 0x7f; // lower 7 bits
>> + unsigned funct3 = (faulty_instruction >> 12) & 0x7; // bits
>> 12-14, inclusive
>> + switch (opcode) {
>> + case 0b0000011: // loads
>> + switch (funct3) {
>> + case 0b000: // lb
>> + case 0b001: // lh
>> + case 0b010: // lw
>> +#if __riscv_xlen == 64
>> + case 0b011: // ld
>> +#endif
>> + case 0b100: // lbu
>> + case 0b101: // lhu
>> + return SignalContext::READ;
>> + default:
>> + return SignalContext::UNKNOWN;
>> + }
>> + case 0b0100011: // stores
>> + switch (funct3) {
>> + case 0b000: // sb
>> + case 0b001: // sh
>> + case 0b010: // sw
>> +#if __riscv_xlen == 64
>> + case 0b011: // sd
>> +#endif
>> + return SignalContext::WRITE;
>> + default:
>> + return SignalContext::UNKNOWN;
>> + }
>> +#if __riscv_flen >= 32
>> + case 0b0000111: // floating-point loads
>> + switch (funct3) {
>> + case 0b010: // flw
>> +#if __riscv_flen == 64
>> + case 0b011: // fld
>> +#endif
>> + return SignalContext::READ;
>> + default:
>> + return SignalContext::UNKNOWN;
>> + }
>> + case 0b0100111: // floating-point stores
>> + switch (funct3) {
>> + case 0b010: // fsw
>> +#if __riscv_flen == 64
>> + case 0b011: // fsd
>> +#endif
>> + return SignalContext::WRITE;
>> + default:
>> + return SignalContext::UNKNOWN;
>> + }
>> +#endif
>> + default:
>> + return SignalContext::UNKNOWN;
>> + }
>> #else
>> (void)ucontext;
>> return UNKNOWN; // FIXME: Implement.
>> @@ -2011,7 +2130,9 @@ void CheckASLR() {
>> }
>>
>> if (UNLIKELY(paxflags & CTL_PROC_PAXFLAGS_ASLR)) {
>> - Printf("This sanitizer is not compatible with enabled ASLR\n");
>> + Printf("This sanitizer is not compatible with enabled ASLR.\n"
>> + "To disable ASLR, please run \"paxctl +a %s\" and try
>> again.\n",
>> + GetArgv()[0]);
>> Die();
>> }
>> #elif SANITIZER_PPC64V2
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_linux.h
>> b/libsanitizer/sanitizer_common/sanitizer_linux.h
>> index c28347ad963..c162d1ca5d2 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_linux.h
>> +++ b/libsanitizer/sanitizer_common/sanitizer_linux.h
>> @@ -25,6 +25,7 @@
>> #include "sanitizer_posix.h"
>>
>> struct link_map; // Opaque type returned by dlopen().
>> +struct utsname;
>>
>> namespace __sanitizer {
>> // Dirent structure for getdents(). Note that this structure is
>> different from
>> @@ -65,6 +66,7 @@ void internal_sigdelset(__sanitizer_sigset_t *set,
>> int signum);
>> uptr internal_clone(int (*fn)(void *), void *child_stack, int
>> flags, void *arg,
>> int *parent_tidptr, void *newtls, int
>> *child_tidptr);
>> #endif
>> +int internal_uname(struct utsname *buf);
>> #elif SANITIZER_FREEBSD
>> void internal_sigdelset(__sanitizer_sigset_t *set, int signum);
>> #elif SANITIZER_NETBSD
>> diff --git
>> a/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp
>> b/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp
>> index e09d568d802..4d17c9686e4 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp
>> @@ -35,6 +35,10 @@
>> #include <sys/resource.h>
>> #include <syslog.h>
>>
>> +#if !defined(ElfW)
>> +#define ElfW(type) Elf_##type
>> +#endif
>> +
>> #if SANITIZER_FREEBSD
>> #include <pthread_np.h>
>> #include <osreldate.h>
>> @@ -50,6 +54,7 @@
>> #if SANITIZER_NETBSD
>> #include <sys/sysctl.h>
>> #include <sys/tls.h>
>> +#include <lwp.h>
>> #endif
>>
>> #if SANITIZER_SOLARIS
>> @@ -399,13 +404,7 @@ uptr ThreadSelf() {
>>
>> #if SANITIZER_NETBSD
>> static struct tls_tcb * ThreadSelfTlsTcb() {
>> - struct tls_tcb * tcb;
>> -# ifdef __HAVE___LWP_GETTCB_FAST
>> - tcb = (struct tls_tcb *)__lwp_gettcb_fast();
>> -# elif defined(__HAVE___LWP_GETPRIVATE_FAST)
>> - tcb = (struct tls_tcb *)__lwp_getprivate_fast();
>> -# endif
>> - return tcb;
>> + return (struct tls_tcb *)_lwp_getprivate();
>> }
>>
>> uptr ThreadSelf() {
>> @@ -698,13 +697,9 @@ u32 GetNumberOfCPUs() {
>> #elif SANITIZER_SOLARIS
>> return sysconf(_SC_NPROCESSORS_ONLN);
>> #else
>> -#if defined(CPU_COUNT)
>> cpu_set_t CPUs;
>> CHECK_EQ(sched_getaffinity(0, sizeof(cpu_set_t), &CPUs), 0);
>> return CPU_COUNT(&CPUs);
>> -#else
>> - return 1;
>> -#endif
>> #endif
>> }
>>
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_linux_s390.cpp
>> b/libsanitizer/sanitizer_common/sanitizer_linux_s390.cpp
>> index 41e187eaf8d..bb2f5b5f9f7 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_linux_s390.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_linux_s390.cpp
>> @@ -15,19 +15,20 @@
>>
>> #if SANITIZER_LINUX && SANITIZER_S390
>>
>> -#include "sanitizer_libc.h"
>> -#include "sanitizer_linux.h"
>> -
>> +#include <dlfcn.h>
>> #include <errno.h>
>> #include <sys/syscall.h>
>> #include <sys/utsname.h>
>> #include <unistd.h>
>>
>> +#include "sanitizer_libc.h"
>> +#include "sanitizer_linux.h"
>> +
>> namespace __sanitizer {
>>
>> // --------------- sanitizer_libc.h
>> uptr internal_mmap(void *addr, uptr length, int prot, int flags,
>> int fd,
>> - OFF_T offset) {
>> + u64 offset) {
>> struct s390_mmap_params {
>> unsigned long addr;
>> unsigned long length;
>> @@ -123,7 +124,7 @@ static bool FixedCVE_2016_2143() {
>> struct utsname buf;
>> unsigned int major, minor, patch = 0;
>> // This should never fail, but just in case...
>> - if (uname(&buf))
>> + if (internal_uname(&buf))
>> return false;
>> const char *ptr = buf.release;
>> major = internal_simple_strtoll(ptr, &ptr, 10);
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_mac.cpp
>> b/libsanitizer/sanitizer_common/sanitizer_mac.cpp
>> index b971ad058e9..7550545ea6f 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_mac.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_mac.cpp
>> @@ -30,6 +30,7 @@
>> #include "sanitizer_placement_new.h"
>> #include "sanitizer_platform_limits_posix.h"
>> #include "sanitizer_procmaps.h"
>> +#include "sanitizer_ptrauth.h"
>>
>> #if !SANITIZER_IOS
>> #include <crt_externs.h> // for _NSGetEnviron
>> @@ -37,7 +38,7 @@
>> extern char **environ;
>> #endif
>>
>> -#if defined(__has_include) && __has_include(<os/trace.h>) &&
>> defined(__BLOCKS__)
>> +#if defined(__has_include) && __has_include(<os/trace.h>)
>> #define SANITIZER_OS_TRACE 1
>> #include <os/trace.h>
>> #else
>> @@ -208,6 +209,10 @@ uptr internal_getpid() {
>> return getpid();
>> }
>>
>> +int internal_dlinfo(void *handle, int request, void *p) {
>> + UNIMPLEMENTED();
>> +}
>> +
>> int internal_sigaction(int signum, const void *act, void *oldact) {
>> return sigaction(signum,
>> (const struct sigaction *)act, (struct sigaction
>> *)oldact);
>> @@ -242,7 +247,8 @@ int internal_sysctlbyname(const char *sname, void
>> *oldp, uptr *oldlenp,
>> (size_t)newlen);
>> }
>>
>> -static fd_t internal_spawn_impl(const char *argv[], pid_t *pid) {
>> +static fd_t internal_spawn_impl(const char *argv[], const char *envp[],
>> + pid_t *pid) {
>> fd_t master_fd = kInvalidFd;
>> fd_t slave_fd = kInvalidFd;
>>
>> @@ -298,8 +304,8 @@ static fd_t internal_spawn_impl(const char
>> *argv[], pid_t *pid) {
>>
>> // posix_spawn
>> char **argv_casted = const_cast<char **>(argv);
>> - char **env = GetEnviron();
>> - res = posix_spawn(pid, argv[0], &acts, &attrs, argv_casted, env);
>> + char **envp_casted = const_cast<char **>(envp);
>> + res = posix_spawn(pid, argv[0], &acts, &attrs, argv_casted,
>> envp_casted);
>> if (res != 0) return kInvalidFd;
>>
>> // Disable echo in the new terminal, disable CR.
>> @@ -316,7 +322,7 @@ static fd_t internal_spawn_impl(const char
>> *argv[], pid_t *pid) {
>> return fd;
>> }
>>
>> -fd_t internal_spawn(const char *argv[], pid_t *pid) {
>> +fd_t internal_spawn(const char *argv[], const char *envp[], pid_t
>> *pid) {
>> // The client program may close its stdin and/or stdout and/or
>> stderr thus
>> // allowing open/posix_openpt to reuse file descriptors 0, 1 or
>> 2. In this
>> // case the communication is broken if either the parent or the
>> child tries to
>> @@ -331,7 +337,7 @@ fd_t internal_spawn(const char *argv[], pid_t
>> *pid) {
>> break;
>> }
>>
>> - fd_t fd = internal_spawn_impl(argv, pid);
>> + fd_t fd = internal_spawn_impl(argv, envp, pid);
>>
>> for (; count > 0; count--) {
>> internal_close(low_fds[count]);
>> @@ -623,19 +629,13 @@ MacosVersion GetMacosVersionInternal() {
>> if (*p != '.') return MACOS_VERSION_UNKNOWN;
>>
>> switch (major) {
>> - case 9: return MACOS_VERSION_LEOPARD;
>> - case 10: return MACOS_VERSION_SNOW_LEOPARD;
>> case 11: return MACOS_VERSION_LION;
>> case 12: return MACOS_VERSION_MOUNTAIN_LION;
>> case 13: return MACOS_VERSION_MAVERICKS;
>> case 14: return MACOS_VERSION_YOSEMITE;
>> case 15: return MACOS_VERSION_EL_CAPITAN;
>> case 16: return MACOS_VERSION_SIERRA;
>> - case 17:
>> - // Not a typo, 17.5 Darwin Kernel Version maps to High Sierra
>> 10.13.4.
>> - if (minor >= 5)
>> - return MACOS_VERSION_HIGH_SIERRA_DOT_RELEASE_4;
>> - return MACOS_VERSION_HIGH_SIERRA;
>> + case 17: return MACOS_VERSION_HIGH_SIERRA;
>> case 18: return MACOS_VERSION_MOJAVE;
>> case 19: return MACOS_VERSION_CATALINA;
>> default:
>> @@ -656,13 +656,21 @@ MacosVersion GetMacosVersion() {
>> return result;
>> }
>>
>> -bool PlatformHasDifferentMemcpyAndMemmove() {
>> - // On OS X 10.7 memcpy() and memmove() are both resolved
>> - // into memmove$VARIANT$sse42.
>> - // See also https://github.com/google/sanitizers/issues/34.
>> - // TODO(glider): need to check dynamically that memcpy() and
>> memmove() are
>> - // actually the same function.
>> - return GetMacosVersion() == MACOS_VERSION_SNOW_LEOPARD;
>> +DarwinKernelVersion GetDarwinKernelVersion() {
>> + char buf[100];
>> + size_t len = sizeof(buf);
>> + int res = internal_sysctlbyname("kern.osrelease", buf, &len,
>> nullptr, 0);
>> + CHECK_EQ(res, 0);
>> +
>> + // Format: <major>.<minor>.<patch>\0
>> + CHECK_GE(len, 6);
>> + const char *p = buf;
>> + u16 major = internal_simple_strtoll(p, &p, /*base=*/10);
>> + CHECK_EQ(*p, '.');
>> + p += 1;
>> + u16 minor = internal_simple_strtoll(p, &p, /*base=*/10);
>> +
>> + return DarwinKernelVersion(major, minor);
>> }
>>
>> uptr GetRSS() {
>> @@ -677,13 +685,13 @@ uptr GetRSS() {
>> return info.resident_size;
>> }
>>
>> -void *internal_start_thread(void(*func)(void *arg), void *arg) {
>> +void *internal_start_thread(void *(*func)(void *arg), void *arg) {
>> // Start the thread with signals blocked, otherwise it can steal
>> user signals.
>> __sanitizer_sigset_t set, old;
>> internal_sigfillset(&set);
>> internal_sigprocmask(SIG_SETMASK, &set, &old);
>> pthread_t th;
>> - pthread_create(&th, 0, (void*(*)(void *arg))func, arg);
>> + pthread_create(&th, 0, func, arg);
>> internal_sigprocmask(SIG_SETMASK, &old, 0);
>> return th;
>> }
>> @@ -760,16 +768,24 @@ bool SignalContext::IsTrueFaultingAddress()
>> const {
>> return si->si_signo == SIGSEGV && si->si_code != 0;
>> }
>>
>> +#if defined(__aarch64__) && defined(arm_thread_state64_get_sp)
>> + #define AARCH64_GET_REG(r) \
>> + (uptr)ptrauth_strip( \
>> + (void
>> *)arm_thread_state64_get_##r(ucontext->uc_mcontext->__ss), 0)
>> +#else
>> + #define AARCH64_GET_REG(r) ucontext->uc_mcontext->__ss.__##r
>> +#endif
>> +
>> static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
>> ucontext_t *ucontext = (ucontext_t*)context;
>> # if defined(__aarch64__)
>> - *pc = ucontext->uc_mcontext->__ss.__pc;
>> + *pc = AARCH64_GET_REG(pc);
>> # if defined(__IPHONE_8_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >=
>> __IPHONE_8_0
>> - *bp = ucontext->uc_mcontext->__ss.__fp;
>> + *bp = AARCH64_GET_REG(fp);
>> # else
>> - *bp = ucontext->uc_mcontext->__ss.__lr;
>> + *bp = AARCH64_GET_REG(lr);
>> # endif
>> - *sp = ucontext->uc_mcontext->__ss.__sp;
>> + *sp = AARCH64_GET_REG(sp);
>> # elif defined(__x86_64__)
>> *pc = ucontext->uc_mcontext->__ss.__rip;
>> *bp = ucontext->uc_mcontext->__ss.__rbp;
>> @@ -787,13 +803,16 @@ static void GetPcSpBp(void *context, uptr *pc,
>> uptr *sp, uptr *bp) {
>> # endif
>> }
>>
>> -void SignalContext::InitPcSpBp() { GetPcSpBp(context, &pc, &sp, &bp); }
>> +void SignalContext::InitPcSpBp() {
>> + addr = (uptr)ptrauth_strip((void *)addr, 0);
>> + GetPcSpBp(context, &pc, &sp, &bp);
>> +}
>>
>> void InitializePlatformEarly() {
>> - // Only use xnu_fast_mmap when on x86_64 and the OS supports it.
>> + // Only use xnu_fast_mmap when on x86_64 and the kernel supports it.
>> use_xnu_fast_mmap =
>> #if defined(__x86_64__)
>> - GetMacosVersion() >= MACOS_VERSION_HIGH_SIERRA_DOT_RELEASE_4;
>> + GetDarwinKernelVersion() >= DarwinKernelVersion(17, 5);
>> #else
>> false;
>> #endif
>> @@ -1123,6 +1142,8 @@ void SignalContext::DumpAllRegisters(void
>> *context) {
>> ucontext_t *ucontext = (ucontext_t*)context;
>> # define DUMPREG64(r) \
>> Printf("%s = 0x%016llx ", #r, ucontext->uc_mcontext->__ss.__
>> ## r);
>> +# define DUMPREGA64(r) \
>> + Printf(" %s = 0x%016llx ", #r, AARCH64_GET_REG(r));
>> # define DUMPREG32(r) \
>> Printf("%s = 0x%08x ", #r, ucontext->uc_mcontext->__ss.__ ## r);
>> # define DUMPREG_(r) Printf(" "); DUMPREG(r);
>> @@ -1148,7 +1169,7 @@ void SignalContext::DumpAllRegisters(void
>> *context) {
>> DUMPREG(x[16]); DUMPREG(x[17]); DUMPREG(x[18]); DUMPREG(x[19]);
>> Printf("\n");
>> DUMPREG(x[20]); DUMPREG(x[21]); DUMPREG(x[22]); DUMPREG(x[23]);
>> Printf("\n");
>> DUMPREG(x[24]); DUMPREG(x[25]); DUMPREG(x[26]); DUMPREG(x[27]);
>> Printf("\n");
>> - DUMPREG(x[28]); DUMPREG___(fp); DUMPREG___(lr); DUMPREG___(sp);
>> Printf("\n");
>> + DUMPREG(x[28]); DUMPREGA64(fp); DUMPREGA64(lr); DUMPREGA64(sp);
>> Printf("\n");
>> # elif defined(__arm__)
>> # define DUMPREG(r) DUMPREG32(r)
>> DUMPREG_(r[0]); DUMPREG_(r[1]); DUMPREG_(r[2]); DUMPREG_(r[3]);
>> Printf("\n");
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_mac.h
>> b/libsanitizer/sanitizer_common/sanitizer_mac.h
>> index 2257883084e..34dc2c05dcf 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_mac.h
>> +++ b/libsanitizer/sanitizer_common/sanitizer_mac.h
>> @@ -33,22 +33,35 @@ struct MemoryMappingLayoutData {
>> enum MacosVersion {
>> MACOS_VERSION_UNINITIALIZED = 0,
>> MACOS_VERSION_UNKNOWN,
>> - MACOS_VERSION_LEOPARD,
>> - MACOS_VERSION_SNOW_LEOPARD,
>> - MACOS_VERSION_LION,
>> + MACOS_VERSION_LION, // macOS 10.7; oldest currently supported
>> MACOS_VERSION_MOUNTAIN_LION,
>> MACOS_VERSION_MAVERICKS,
>> MACOS_VERSION_YOSEMITE,
>> MACOS_VERSION_EL_CAPITAN,
>> MACOS_VERSION_SIERRA,
>> MACOS_VERSION_HIGH_SIERRA,
>> - MACOS_VERSION_HIGH_SIERRA_DOT_RELEASE_4,
>> MACOS_VERSION_MOJAVE,
>> MACOS_VERSION_CATALINA,
>> MACOS_VERSION_UNKNOWN_NEWER
>> };
>>
>> +struct DarwinKernelVersion {
>> + u16 major;
>> + u16 minor;
>> +
>> + DarwinKernelVersion(u16 major, u16 minor) : major(major),
>> minor(minor) {}
>> +
>> + bool operator==(const DarwinKernelVersion &other) const {
>> + return major == other.major && minor == other.minor;
>> + }
>> + bool operator>=(const DarwinKernelVersion &other) const {
>> + return major >= other.major ||
>> + (major == other.major && minor >= other.minor);
>> + }
>> +};
>> +
>> MacosVersion GetMacosVersion();
>> +DarwinKernelVersion GetDarwinKernelVersion();
>>
>> char **GetEnviron();
>>
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_malloc_mac.inc
>> b/libsanitizer/sanitizer_common/sanitizer_malloc_mac.inc
>> index 11adbe5c25b..647bcdfe105 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_malloc_mac.inc
>> +++ b/libsanitizer/sanitizer_common/sanitizer_malloc_mac.inc
>> @@ -61,12 +61,10 @@ INTERCEPTOR(malloc_zone_t *, malloc_create_zone,
>> malloc_zone_t *new_zone = (malloc_zone_t *)p;
>> internal_memcpy(new_zone, &sanitizer_zone, sizeof(sanitizer_zone));
>> new_zone->zone_name = NULL; // The name will be changed anyway.
>> - if (GetMacosVersion() >= MACOS_VERSION_LION) {
>> - // Prevent the client app from overwriting the zone contents.
>> - // Library functions that need to modify the zone will set
>> PROT_WRITE on it.
>> - // This matches the behavior of malloc_create_zone() on OSX 10.7
>> and higher.
>> - mprotect(new_zone, allocated_size, PROT_READ);
>> - }
>> + // Prevent the client app from overwriting the zone contents.
>> + // Library functions that need to modify the zone will set
>> PROT_WRITE on it.
>> + // This matches the behavior of malloc_create_zone() on OSX 10.7
>> and higher.
>> + mprotect(new_zone, allocated_size, PROT_READ);
>> // We're explicitly *NOT* registering the zone.
>> return new_zone;
>> }
>> @@ -75,11 +73,9 @@ INTERCEPTOR(void, malloc_destroy_zone,
>> malloc_zone_t *zone) {
>> COMMON_MALLOC_ENTER();
>> // We don't need to do anything here. We're not registering new
>> zones, so we
>> // don't to unregister. Just un-mprotect and free() the zone.
>> - if (GetMacosVersion() >= MACOS_VERSION_LION) {
>> - uptr page_size = GetPageSizeCached();
>> - uptr allocated_size = RoundUpTo(sizeof(sanitizer_zone), page_size);
>> - mprotect(zone, allocated_size, PROT_READ | PROT_WRITE);
>> - }
>> + uptr page_size = GetPageSizeCached();
>> + uptr allocated_size = RoundUpTo(sizeof(sanitizer_zone), page_size);
>> + mprotect(zone, allocated_size, PROT_READ | PROT_WRITE);
>> if (zone->zone_name) {
>> COMMON_MALLOC_FREE((void *)zone->zone_name);
>> }
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_netbsd.cpp
>> b/libsanitizer/sanitizer_common/sanitizer_netbsd.cpp
>> index 4e74f6a3b51..d9aff51d8ae 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_netbsd.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_netbsd.cpp
>> @@ -95,7 +95,7 @@ static void *GetRealLibcAddress(const char *symbol) {
>>
>> // --------------- sanitizer_libc.h
>> uptr internal_mmap(void *addr, uptr length, int prot, int flags,
>> int fd,
>> - OFF_T offset) {
>> + u64 offset) {
>> CHECK(&__mmap);
>> return (uptr)__mmap(addr, length, prot, flags, fd, 0, offset);
>> }
>> @@ -265,6 +265,11 @@ uptr internal_getppid() {
>> return _REAL(getppid);
>> }
>>
>> +int internal_dlinfo(void *handle, int request, void *p) {
>> + DEFINE__REAL(int, dlinfo, void *a, int b, void *c);
>> + return _REAL(dlinfo, handle, request, p);
>> +}
>> +
>> uptr internal_getdents(fd_t fd, void *dirp, unsigned int count) {
>> DEFINE__REAL(int, __getdents30, int a, void *b, size_t c);
>> return _REAL(__getdents30, fd, dirp, count);
>> diff --git
>> a/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h
>> b/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h
>> index 61a6b82ef81..9dd6d285f59 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h
>> +++ b/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h
>> @@ -90,6 +90,24 @@
>> # define SI_IOS 0
>> #endif
>>
>> +#if SANITIZER_IOSSIM
>> +# define SI_IOSSIM 1
>> +#else
>> +# define SI_IOSSIM 0
>> +#endif
>> +
>> +#if SANITIZER_WATCHOS
>> +# define SI_WATCHOS 1
>> +#else
>> +# define SI_WATCHOS 0
>> +#endif
>> +
>> +#if SANITIZER_TVOS
>> +# define SI_TVOS 1
>> +#else
>> +# define SI_TVOS 0
>> +#endif
>> +
>> #if SANITIZER_FUCHSIA
>> # define SI_NOT_FUCHSIA 0
>> #else
>> @@ -575,5 +593,11 @@
>> #define SANITIZER_INTERCEPT_ATEXIT SI_NETBSD
>> #define SANITIZER_INTERCEPT_PTHREAD_ATFORK SI_NETBSD
>> #define SANITIZER_INTERCEPT_GETENTROPY SI_FREEBSD
>> +#define SANITIZER_INTERCEPT_QSORT \
>> + (SI_POSIX && !SI_IOSSIM && !SI_WATCHOS && !SI_TVOS && !SI_ANDROID)
>> +#define SANITIZER_INTERCEPT_QSORT_R (SI_LINUX && !SI_ANDROID)
>> +#define SANITIZER_INTERCEPT_SIGALTSTACK SI_POSIX
>> +#define SANITIZER_INTERCEPT_UNAME (SI_POSIX && !SI_FREEBSD)
>> +#define SANITIZER_INTERCEPT___XUNAME SI_FREEBSD
>>
>> #endif // #ifndef SANITIZER_PLATFORM_INTERCEPTORS_H
>> diff --git
>> a/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.cpp
>> b/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.cpp
>> index 2d1bb1a12da..dcc6c71c07d 100644
>> ---
>> a/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.cpp
>> +++
>> b/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.cpp
>> @@ -15,342 +15,348 @@
>>
>> #if SANITIZER_FREEBSD
>>
>> +#include <sys/capsicum.h>
>> +#include <sys/consio.h>
>> +#include <sys/filio.h>
>> +#include <sys/ipc.h>
>> +#include <sys/kbio.h>
>> +#include <sys/link_elf.h>
>> +#include <sys/mman.h>
>> +#include <sys/mount.h>
>> +#include <sys/mqueue.h>
>> +#include <sys/msg.h>
>> +#include <sys/mtio.h>
>> +#include <sys/ptrace.h>
>> +#include <sys/resource.h>
>> +#include <sys/signal.h>
>> +#include <sys/socket.h>
>> +#include <sys/sockio.h>
>> +#include <sys/soundcard.h>
>> +#include <sys/stat.h>
>> +#include <sys/statvfs.h>
>> +#include <sys/time.h>
>> +#include <sys/timeb.h>
>> +#include <sys/times.h>
>> +#include <sys/timespec.h>
>> +#include <sys/types.h>
>> +#include <sys/ucontext.h>
>> +#include <sys/utsname.h>
>> +//
>> #include <arpa/inet.h>
>> +#include <net/ethernet.h>
>> +#include <net/if.h>
>> +#include <net/ppp_defs.h>
>> +#include <net/route.h>
>> +#include <netdb.h>
>> +#include <netinet/in.h>
>> +#include <netinet/ip_mroute.h>
>> +//
>> #include <dirent.h>
>> -#include <fts.h>
>> +#include <dlfcn.h>
>> #include <fstab.h>
>> +#include <fts.h>
>> +#include <glob.h>
>> #include <grp.h>
>> +#include <ifaddrs.h>
>> #include <limits.h>
>> -#include <net/if.h>
>> -#include <netdb.h>
>> #include <poll.h>
>> #include <pthread.h>
>> #include <pwd.h>
>> #include <regex.h>
>> +#include <semaphore.h>
>> #include <signal.h>
>> #include <stddef.h>
>> -#include <sys/mman.h>
>> -#include <sys/capsicum.h>
>> -#include <sys/resource.h>
>> -#include <sys/stat.h>
>> -#include <sys/time.h>
>> -#include <sys/times.h>
>> -#include <sys/types.h>
>> -#include <sys/utsname.h>
>> -#include <termios.h>
>> -#include <time.h>
>> -
>> -#include <net/route.h>
>> -#include <sys/mount.h>
>> -#include <sys/sockio.h>
>> -#include <sys/socket.h>
>> -#include <sys/filio.h>
>> -#include <sys/signal.h>
>> -#include <sys/timespec.h>
>> -#include <sys/timeb.h>
>> -#include <sys/mqueue.h>
>> -#include <sys/msg.h>
>> -#include <sys/ipc.h>
>> -#include <sys/msg.h>
>> -#include <sys/statvfs.h>
>> -#include <sys/soundcard.h>
>> -#include <sys/mtio.h>
>> -#include <sys/consio.h>
>> -#include <sys/kbio.h>
>> -#include <sys/link_elf.h>
>> -#include <netinet/ip_mroute.h>
>> -#include <netinet/in.h>
>> -#include <net/ethernet.h>
>> -#include <net/ppp_defs.h>
>> -#include <glob.h>
>> #include <stdio.h>
>> #include <stringlist.h>
>> #include <term.h>
>> +#include <termios.h>
>> +#include <time.h>
>> +#include <utime.h>
>> #include <utmpx.h>
>> -#include <wchar.h>
>> #include <vis.h>
>> +#include <wchar.h>
>> +#include <wordexp.h>
>>
>> #define _KERNEL // to declare 'shminfo' structure
>> -# include <sys/shm.h>
>> +#include <sys/shm.h>
>> #undef _KERNEL
>>
>> #undef INLINE // to avoid clashes with sanitizers' definitions
>>
>> #undef IOC_DIRMASK
>>
>> -# include <utime.h>
>> -# include <sys/ptrace.h>
>> -# include <semaphore.h>
>> -
>> -#include <ifaddrs.h>
>> -#include <sys/ucontext.h>
>> -#include <wordexp.h>
>> -
>> // Include these after system headers to avoid name clashes and
>> ambiguities.
>> #include "sanitizer_internal_defs.h"
>> +#include "sanitizer_libc.h"
>> #include "sanitizer_platform_limits_freebsd.h"
>>
>> namespace __sanitizer {
>> - unsigned struct_cap_rights_sz = sizeof(cap_rights_t);
>> - unsigned struct_utsname_sz = sizeof(struct utsname);
>> - unsigned struct_stat_sz = sizeof(struct stat);
>> - unsigned struct_rusage_sz = sizeof(struct rusage);
>> - unsigned struct_tm_sz = sizeof(struct tm);
>> - unsigned struct_passwd_sz = sizeof(struct passwd);
>> - unsigned struct_group_sz = sizeof(struct group);
>> - unsigned siginfo_t_sz = sizeof(siginfo_t);
>> - unsigned struct_sigaction_sz = sizeof(struct sigaction);
>> - unsigned struct_itimerval_sz = sizeof(struct itimerval);
>> - unsigned pthread_t_sz = sizeof(pthread_t);
>> - unsigned pthread_mutex_t_sz = sizeof(pthread_mutex_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);
>> - unsigned gid_t_sz = sizeof(gid_t);
>> - unsigned fpos_t_sz = sizeof(fpos_t);
>> - unsigned mbstate_t_sz = sizeof(mbstate_t);
>> - unsigned sigset_t_sz = sizeof(sigset_t);
>> - unsigned struct_timezone_sz = sizeof(struct timezone);
>> - 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);
>> - unsigned struct_sockaddr_sz = sizeof(struct sockaddr);
>> - unsigned ucontext_t_sz = sizeof(ucontext_t);
>> - unsigned struct_rlimit_sz = sizeof(struct rlimit);
>> - unsigned struct_timespec_sz = sizeof(struct timespec);
>> - unsigned struct_utimbuf_sz = sizeof(struct utimbuf);
>> - unsigned struct_itimerspec_sz = sizeof(struct itimerspec);
>> - unsigned struct_timeb_sz = sizeof(struct timeb);
>> - unsigned struct_msqid_ds_sz = sizeof(struct msqid_ds);
>> - unsigned struct_mq_attr_sz = sizeof(struct mq_attr);
>> - unsigned struct_statvfs_sz = sizeof(struct statvfs);
>> - unsigned struct_shminfo_sz = sizeof(struct shminfo);
>> - unsigned struct_shm_info_sz = sizeof(struct shm_info);
>> - unsigned struct_regmatch_sz = sizeof(regmatch_t);
>> - unsigned struct_regex_sz = sizeof(regex_t);
>> - unsigned struct_fstab_sz = sizeof(struct fstab);
>> - unsigned struct_FTS_sz = sizeof(FTS);
>> - unsigned struct_FTSENT_sz = sizeof(FTSENT);
>> - unsigned struct_StringList_sz = sizeof(StringList);
>> -
>> - const uptr sig_ign = (uptr)SIG_IGN;
>> - const uptr sig_dfl = (uptr)SIG_DFL;
>> - const uptr sig_err = (uptr)SIG_ERR;
>> - const uptr sa_siginfo = (uptr)SA_SIGINFO;
>> -
>> - 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_STAT;
>> - unsigned struct_utmpx_sz = sizeof(struct utmpx);
>> -
>> - int map_fixed = MAP_FIXED;
>> -
>> - int af_inet = (int)AF_INET;
>> - int af_inet6 = (int)AF_INET6;
>> -
>> - uptr __sanitizer_in_addr_sz(int af) {
>> - if (af == AF_INET)
>> - return sizeof(struct in_addr);
>> - else if (af == AF_INET6)
>> - return sizeof(struct in6_addr);
>> - else
>> - return 0;
>> - }
>> -
>> - unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
>> - int glob_nomatch = GLOB_NOMATCH;
>> - int glob_altdirfunc = GLOB_ALTDIRFUNC;
>> -
>> - unsigned path_max = PATH_MAX;
>> -
>> - // ioctl arguments
>> - unsigned struct_ifreq_sz = sizeof(struct ifreq);
>> - unsigned struct_termios_sz = sizeof(struct termios);
>> - unsigned struct_winsize_sz = sizeof(struct winsize);
>> +void *__sanitizer_get_link_map_by_dlopen_handle(void *handle) {
>> + void *p = nullptr;
>> + return internal_dlinfo(handle, RTLD_DI_LINKMAP, &p) == 0 ? p :
>> nullptr;
>> +}
>> +
>> +unsigned struct_cap_rights_sz = sizeof(cap_rights_t);
>> +unsigned struct_utsname_sz = sizeof(struct utsname);
>> +unsigned struct_stat_sz = sizeof(struct stat);
>> +unsigned struct_rusage_sz = sizeof(struct rusage);
>> +unsigned struct_tm_sz = sizeof(struct tm);
>> +unsigned struct_passwd_sz = sizeof(struct passwd);
>> +unsigned struct_group_sz = sizeof(struct group);
>> +unsigned siginfo_t_sz = sizeof(siginfo_t);
>> +unsigned struct_sigaction_sz = sizeof(struct sigaction);
>> +unsigned struct_stack_t_sz = sizeof(stack_t);
>> +unsigned struct_itimerval_sz = sizeof(struct itimerval);
>> +unsigned pthread_t_sz = sizeof(pthread_t);
>> +unsigned pthread_mutex_t_sz = sizeof(pthread_mutex_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);
>> +unsigned gid_t_sz = sizeof(gid_t);
>> +unsigned fpos_t_sz = sizeof(fpos_t);
>> +unsigned mbstate_t_sz = sizeof(mbstate_t);
>> +unsigned sigset_t_sz = sizeof(sigset_t);
>> +unsigned struct_timezone_sz = sizeof(struct timezone);
>> +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);
>> +unsigned struct_sockaddr_sz = sizeof(struct sockaddr);
>> +unsigned ucontext_t_sz = sizeof(ucontext_t);
>> +unsigned struct_rlimit_sz = sizeof(struct rlimit);
>> +unsigned struct_timespec_sz = sizeof(struct timespec);
>> +unsigned struct_utimbuf_sz = sizeof(struct utimbuf);
>> +unsigned struct_itimerspec_sz = sizeof(struct itimerspec);
>> +unsigned struct_timeb_sz = sizeof(struct timeb);
>> +unsigned struct_msqid_ds_sz = sizeof(struct msqid_ds);
>> +unsigned struct_mq_attr_sz = sizeof(struct mq_attr);
>> +unsigned struct_statvfs_sz = sizeof(struct statvfs);
>> +unsigned struct_shminfo_sz = sizeof(struct shminfo);
>> +unsigned struct_shm_info_sz = sizeof(struct shm_info);
>> +unsigned struct_regmatch_sz = sizeof(regmatch_t);
>> +unsigned struct_regex_sz = sizeof(regex_t);
>> +unsigned struct_fstab_sz = sizeof(struct fstab);
>> +unsigned struct_FTS_sz = sizeof(FTS);
>> +unsigned struct_FTSENT_sz = sizeof(FTSENT);
>> +unsigned struct_StringList_sz = sizeof(StringList);
>> +
>> +const uptr sig_ign = (uptr)SIG_IGN;
>> +const uptr sig_dfl = (uptr)SIG_DFL;
>> +const uptr sig_err = (uptr)SIG_ERR;
>> +const uptr sa_siginfo = (uptr)SA_SIGINFO;
>> +
>> +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_STAT;
>> +unsigned struct_utmpx_sz = sizeof(struct utmpx);
>> +
>> +int map_fixed = MAP_FIXED;
>> +
>> +int af_inet = (int)AF_INET;
>> +int af_inet6 = (int)AF_INET6;
>> +
>> +uptr __sanitizer_in_addr_sz(int af) {
>> + if (af == AF_INET)
>> + return sizeof(struct in_addr);
>> + else if (af == AF_INET6)
>> + return sizeof(struct in6_addr);
>> + else
>> + return 0;
>> +}
>> +
>> +unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
>> +int glob_nomatch = GLOB_NOMATCH;
>> +int glob_altdirfunc = GLOB_ALTDIRFUNC;
>> +
>> +unsigned path_max = PATH_MAX;
>> +
>> +// ioctl arguments
>> +unsigned struct_ifreq_sz = sizeof(struct ifreq);
>> +unsigned struct_termios_sz = sizeof(struct termios);
>> +unsigned struct_winsize_sz = sizeof(struct winsize);
>> #if SOUND_VERSION >= 0x040000
>> - unsigned struct_copr_buffer_sz = 0;
>> - unsigned struct_copr_debug_buf_sz = 0;
>> - unsigned struct_copr_msg_sz = 0;
>> +unsigned struct_copr_buffer_sz = 0;
>> +unsigned struct_copr_debug_buf_sz = 0;
>> +unsigned struct_copr_msg_sz = 0;
>> #else
>> - unsigned struct_copr_buffer_sz = sizeof(struct copr_buffer);
>> - unsigned struct_copr_debug_buf_sz = sizeof(struct copr_debug_buf);
>> - unsigned struct_copr_msg_sz = sizeof(struct copr_msg);
>> +unsigned struct_copr_buffer_sz = sizeof(struct copr_buffer);
>> +unsigned struct_copr_debug_buf_sz = sizeof(struct copr_debug_buf);
>> +unsigned struct_copr_msg_sz = sizeof(struct copr_msg);
>> #endif
>> - unsigned struct_midi_info_sz = sizeof(struct midi_info);
>> - unsigned struct_mtget_sz = sizeof(struct mtget);
>> - unsigned struct_mtop_sz = sizeof(struct mtop);
>> - unsigned struct_sbi_instrument_sz = sizeof(struct sbi_instrument);
>> - unsigned struct_seq_event_rec_sz = sizeof(struct seq_event_rec);
>> - unsigned struct_synth_info_sz = sizeof(struct synth_info);
>> - unsigned struct_audio_buf_info_sz = sizeof(struct audio_buf_info);
>> - unsigned struct_ppp_stats_sz = sizeof(struct ppp_stats);
>> - unsigned struct_sioc_sg_req_sz = sizeof(struct sioc_sg_req);
>> - unsigned struct_sioc_vif_req_sz = sizeof(struct sioc_vif_req);
>> - const unsigned long __sanitizer_bufsiz = BUFSIZ;
>> -
>> - const unsigned IOCTL_NOT_PRESENT = 0;
>> -
>> - unsigned IOCTL_FIOASYNC = FIOASYNC;
>> - unsigned IOCTL_FIOCLEX = FIOCLEX;
>> - unsigned IOCTL_FIOGETOWN = FIOGETOWN;
>> - unsigned IOCTL_FIONBIO = FIONBIO;
>> - unsigned IOCTL_FIONCLEX = FIONCLEX;
>> - unsigned IOCTL_FIOSETOWN = FIOSETOWN;
>> - unsigned IOCTL_SIOCADDMULTI = SIOCADDMULTI;
>> - unsigned IOCTL_SIOCATMARK = SIOCATMARK;
>> - unsigned IOCTL_SIOCDELMULTI = SIOCDELMULTI;
>> - unsigned IOCTL_SIOCGIFADDR = SIOCGIFADDR;
>> - unsigned IOCTL_SIOCGIFBRDADDR = SIOCGIFBRDADDR;
>> - unsigned IOCTL_SIOCGIFCONF = SIOCGIFCONF;
>> - unsigned IOCTL_SIOCGIFDSTADDR = SIOCGIFDSTADDR;
>> - unsigned IOCTL_SIOCGIFFLAGS = SIOCGIFFLAGS;
>> - unsigned IOCTL_SIOCGIFMETRIC = SIOCGIFMETRIC;
>> - unsigned IOCTL_SIOCGIFMTU = SIOCGIFMTU;
>> - unsigned IOCTL_SIOCGIFNETMASK = SIOCGIFNETMASK;
>> - unsigned IOCTL_SIOCGPGRP = SIOCGPGRP;
>> - unsigned IOCTL_SIOCSIFADDR = SIOCSIFADDR;
>> - unsigned IOCTL_SIOCSIFBRDADDR = SIOCSIFBRDADDR;
>> - unsigned IOCTL_SIOCSIFDSTADDR = SIOCSIFDSTADDR;
>> - unsigned IOCTL_SIOCSIFFLAGS = SIOCSIFFLAGS;
>> - unsigned IOCTL_SIOCSIFMETRIC = SIOCSIFMETRIC;
>> - unsigned IOCTL_SIOCSIFMTU = SIOCSIFMTU;
>> - unsigned IOCTL_SIOCSIFNETMASK = SIOCSIFNETMASK;
>> - unsigned IOCTL_SIOCSPGRP = SIOCSPGRP;
>> - unsigned IOCTL_TIOCCONS = TIOCCONS;
>> - unsigned IOCTL_TIOCEXCL = TIOCEXCL;
>> - unsigned IOCTL_TIOCGETD = TIOCGETD;
>> - unsigned IOCTL_TIOCGPGRP = TIOCGPGRP;
>> - unsigned IOCTL_TIOCGWINSZ = TIOCGWINSZ;
>> - unsigned IOCTL_TIOCMBIC = TIOCMBIC;
>> - unsigned IOCTL_TIOCMBIS = TIOCMBIS;
>> - unsigned IOCTL_TIOCMGET = TIOCMGET;
>> - unsigned IOCTL_TIOCMSET = TIOCMSET;
>> - unsigned IOCTL_TIOCNOTTY = TIOCNOTTY;
>> - unsigned IOCTL_TIOCNXCL = TIOCNXCL;
>> - unsigned IOCTL_TIOCOUTQ = TIOCOUTQ;
>> - unsigned IOCTL_TIOCPKT = TIOCPKT;
>> - unsigned IOCTL_TIOCSCTTY = TIOCSCTTY;
>> - unsigned IOCTL_TIOCSETD = TIOCSETD;
>> - unsigned IOCTL_TIOCSPGRP = TIOCSPGRP;
>> - unsigned IOCTL_TIOCSTI = TIOCSTI;
>> - unsigned IOCTL_TIOCSWINSZ = TIOCSWINSZ;
>> - unsigned IOCTL_SIOCGETSGCNT = SIOCGETSGCNT;
>> - unsigned IOCTL_SIOCGETVIFCNT = SIOCGETVIFCNT;
>> - unsigned IOCTL_MTIOCGET = MTIOCGET;
>> - unsigned IOCTL_MTIOCTOP = MTIOCTOP;
>> - unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE = SNDCTL_DSP_GETBLKSIZE;
>> - unsigned IOCTL_SNDCTL_DSP_GETFMTS = SNDCTL_DSP_GETFMTS;
>> - unsigned IOCTL_SNDCTL_DSP_NONBLOCK = SNDCTL_DSP_NONBLOCK;
>> - unsigned IOCTL_SNDCTL_DSP_POST = SNDCTL_DSP_POST;
>> - unsigned IOCTL_SNDCTL_DSP_RESET = SNDCTL_DSP_RESET;
>> - unsigned IOCTL_SNDCTL_DSP_SETFMT = SNDCTL_DSP_SETFMT;
>> - unsigned IOCTL_SNDCTL_DSP_SETFRAGMENT = SNDCTL_DSP_SETFRAGMENT;
>> - unsigned IOCTL_SNDCTL_DSP_SPEED = SNDCTL_DSP_SPEED;
>> - unsigned IOCTL_SNDCTL_DSP_STEREO = SNDCTL_DSP_STEREO;
>> - unsigned IOCTL_SNDCTL_DSP_SUBDIVIDE = SNDCTL_DSP_SUBDIVIDE;
>> - unsigned IOCTL_SNDCTL_DSP_SYNC = SNDCTL_DSP_SYNC;
>> - unsigned IOCTL_SNDCTL_FM_4OP_ENABLE = SNDCTL_FM_4OP_ENABLE;
>> - unsigned IOCTL_SNDCTL_FM_LOAD_INSTR = SNDCTL_FM_LOAD_INSTR;
>> - unsigned IOCTL_SNDCTL_MIDI_INFO = SNDCTL_MIDI_INFO;
>> - unsigned IOCTL_SNDCTL_MIDI_PRETIME = SNDCTL_MIDI_PRETIME;
>> - unsigned IOCTL_SNDCTL_SEQ_CTRLRATE = SNDCTL_SEQ_CTRLRATE;
>> - unsigned IOCTL_SNDCTL_SEQ_GETINCOUNT = SNDCTL_SEQ_GETINCOUNT;
>> - unsigned IOCTL_SNDCTL_SEQ_GETOUTCOUNT = SNDCTL_SEQ_GETOUTCOUNT;
>> - unsigned IOCTL_SNDCTL_SEQ_NRMIDIS = SNDCTL_SEQ_NRMIDIS;
>> - unsigned IOCTL_SNDCTL_SEQ_NRSYNTHS = SNDCTL_SEQ_NRSYNTHS;
>> - unsigned IOCTL_SNDCTL_SEQ_OUTOFBAND = SNDCTL_SEQ_OUTOFBAND;
>> - unsigned IOCTL_SNDCTL_SEQ_PANIC = SNDCTL_SEQ_PANIC;
>> - unsigned IOCTL_SNDCTL_SEQ_PERCMODE = SNDCTL_SEQ_PERCMODE;
>> - unsigned IOCTL_SNDCTL_SEQ_RESET = SNDCTL_SEQ_RESET;
>> - unsigned IOCTL_SNDCTL_SEQ_RESETSAMPLES = SNDCTL_SEQ_RESETSAMPLES;
>> - unsigned IOCTL_SNDCTL_SEQ_SYNC = SNDCTL_SEQ_SYNC;
>> - unsigned IOCTL_SNDCTL_SEQ_TESTMIDI = SNDCTL_SEQ_TESTMIDI;
>> - unsigned IOCTL_SNDCTL_SEQ_THRESHOLD = SNDCTL_SEQ_THRESHOLD;
>> - unsigned IOCTL_SNDCTL_SYNTH_INFO = SNDCTL_SYNTH_INFO;
>> - unsigned IOCTL_SNDCTL_SYNTH_MEMAVL = SNDCTL_SYNTH_MEMAVL;
>> - unsigned IOCTL_SNDCTL_TMR_CONTINUE = SNDCTL_TMR_CONTINUE;
>> - unsigned IOCTL_SNDCTL_TMR_METRONOME = SNDCTL_TMR_METRONOME;
>> - unsigned IOCTL_SNDCTL_TMR_SELECT = SNDCTL_TMR_SELECT;
>> - unsigned IOCTL_SNDCTL_TMR_SOURCE = SNDCTL_TMR_SOURCE;
>> - unsigned IOCTL_SNDCTL_TMR_START = SNDCTL_TMR_START;
>> - unsigned IOCTL_SNDCTL_TMR_STOP = SNDCTL_TMR_STOP;
>> - unsigned IOCTL_SNDCTL_TMR_TEMPO = SNDCTL_TMR_TEMPO;
>> - unsigned IOCTL_SNDCTL_TMR_TIMEBASE = SNDCTL_TMR_TIMEBASE;
>> - unsigned IOCTL_SOUND_MIXER_READ_ALTPCM = SOUND_MIXER_READ_ALTPCM;
>> - unsigned IOCTL_SOUND_MIXER_READ_BASS = SOUND_MIXER_READ_BASS;
>> - unsigned IOCTL_SOUND_MIXER_READ_CAPS = SOUND_MIXER_READ_CAPS;
>> - unsigned IOCTL_SOUND_MIXER_READ_CD = SOUND_MIXER_READ_CD;
>> - unsigned IOCTL_SOUND_MIXER_READ_DEVMASK = SOUND_MIXER_READ_DEVMASK;
>> - unsigned IOCTL_SOUND_MIXER_READ_ENHANCE = SOUND_MIXER_READ_ENHANCE;
>> - unsigned IOCTL_SOUND_MIXER_READ_IGAIN = SOUND_MIXER_READ_IGAIN;
>> - unsigned IOCTL_SOUND_MIXER_READ_IMIX = SOUND_MIXER_READ_IMIX;
>> - unsigned IOCTL_SOUND_MIXER_READ_LINE = SOUND_MIXER_READ_LINE;
>> - unsigned IOCTL_SOUND_MIXER_READ_LINE1 = SOUND_MIXER_READ_LINE1;
>> - unsigned IOCTL_SOUND_MIXER_READ_LINE2 = SOUND_MIXER_READ_LINE2;
>> - unsigned IOCTL_SOUND_MIXER_READ_LINE3 = SOUND_MIXER_READ_LINE3;
>> - unsigned IOCTL_SOUND_MIXER_READ_LOUD = SOUND_MIXER_READ_LOUD;
>> - unsigned IOCTL_SOUND_MIXER_READ_MIC = SOUND_MIXER_READ_MIC;
>> - unsigned IOCTL_SOUND_MIXER_READ_MUTE = SOUND_MIXER_READ_MUTE;
>> - unsigned IOCTL_SOUND_MIXER_READ_OGAIN = SOUND_MIXER_READ_OGAIN;
>> - unsigned IOCTL_SOUND_MIXER_READ_PCM = SOUND_MIXER_READ_PCM;
>> - unsigned IOCTL_SOUND_MIXER_READ_RECLEV = SOUND_MIXER_READ_RECLEV;
>> - unsigned IOCTL_SOUND_MIXER_READ_RECMASK = SOUND_MIXER_READ_RECMASK;
>> - unsigned IOCTL_SOUND_MIXER_READ_RECSRC = SOUND_MIXER_READ_RECSRC;
>> - unsigned IOCTL_SOUND_MIXER_READ_SPEAKER = SOUND_MIXER_READ_SPEAKER;
>> - unsigned IOCTL_SOUND_MIXER_READ_STEREODEVS =
>> SOUND_MIXER_READ_STEREODEVS;
>> - unsigned IOCTL_SOUND_MIXER_READ_SYNTH = SOUND_MIXER_READ_SYNTH;
>> - unsigned IOCTL_SOUND_MIXER_READ_TREBLE = SOUND_MIXER_READ_TREBLE;
>> - unsigned IOCTL_SOUND_MIXER_READ_VOLUME = SOUND_MIXER_READ_VOLUME;
>> - unsigned IOCTL_SOUND_MIXER_WRITE_ALTPCM = SOUND_MIXER_WRITE_ALTPCM;
>> - unsigned IOCTL_SOUND_MIXER_WRITE_BASS = SOUND_MIXER_WRITE_BASS;
>> - unsigned IOCTL_SOUND_MIXER_WRITE_CD = SOUND_MIXER_WRITE_CD;
>> - unsigned IOCTL_SOUND_MIXER_WRITE_ENHANCE = SOUND_MIXER_WRITE_ENHANCE;
>> - unsigned IOCTL_SOUND_MIXER_WRITE_IGAIN = SOUND_MIXER_WRITE_IGAIN;
>> - unsigned IOCTL_SOUND_MIXER_WRITE_IMIX = SOUND_MIXER_WRITE_IMIX;
>> - unsigned IOCTL_SOUND_MIXER_WRITE_LINE = SOUND_MIXER_WRITE_LINE;
>> - unsigned IOCTL_SOUND_MIXER_WRITE_LINE1 = SOUND_MIXER_WRITE_LINE1;
>> - unsigned IOCTL_SOUND_MIXER_WRITE_LINE2 = SOUND_MIXER_WRITE_LINE2;
>> - unsigned IOCTL_SOUND_MIXER_WRITE_LINE3 = SOUND_MIXER_WRITE_LINE3;
>> - unsigned IOCTL_SOUND_MIXER_WRITE_LOUD = SOUND_MIXER_WRITE_LOUD;
>> - unsigned IOCTL_SOUND_MIXER_WRITE_MIC = SOUND_MIXER_WRITE_MIC;
>> - unsigned IOCTL_SOUND_MIXER_WRITE_MUTE = SOUND_MIXER_WRITE_MUTE;
>> - unsigned IOCTL_SOUND_MIXER_WRITE_OGAIN = SOUND_MIXER_WRITE_OGAIN;
>> - unsigned IOCTL_SOUND_MIXER_WRITE_PCM = SOUND_MIXER_WRITE_PCM;
>> - unsigned IOCTL_SOUND_MIXER_WRITE_RECLEV = SOUND_MIXER_WRITE_RECLEV;
>> - unsigned IOCTL_SOUND_MIXER_WRITE_RECSRC = SOUND_MIXER_WRITE_RECSRC;
>> - unsigned IOCTL_SOUND_MIXER_WRITE_SPEAKER = SOUND_MIXER_WRITE_SPEAKER;
>> - unsigned IOCTL_SOUND_MIXER_WRITE_SYNTH = SOUND_MIXER_WRITE_SYNTH;
>> - unsigned IOCTL_SOUND_MIXER_WRITE_TREBLE = SOUND_MIXER_WRITE_TREBLE;
>> - unsigned IOCTL_SOUND_MIXER_WRITE_VOLUME = SOUND_MIXER_WRITE_VOLUME;
>> - unsigned IOCTL_VT_ACTIVATE = VT_ACTIVATE;
>> - unsigned IOCTL_VT_GETMODE = VT_GETMODE;
>> - unsigned IOCTL_VT_OPENQRY = VT_OPENQRY;
>> - unsigned IOCTL_VT_RELDISP = VT_RELDISP;
>> - unsigned IOCTL_VT_SETMODE = VT_SETMODE;
>> - unsigned IOCTL_VT_WAITACTIVE = VT_WAITACTIVE;
>> - unsigned IOCTL_GIO_SCRNMAP = GIO_SCRNMAP;
>> - unsigned IOCTL_KDDISABIO = KDDISABIO;
>> - unsigned IOCTL_KDENABIO = KDENABIO;
>> - unsigned IOCTL_KDGETLED = KDGETLED;
>> - unsigned IOCTL_KDGETMODE = KDGETMODE;
>> - unsigned IOCTL_KDGKBMODE = KDGKBMODE;
>> - unsigned IOCTL_KDGKBTYPE = KDGKBTYPE;
>> - unsigned IOCTL_KDMKTONE = KDMKTONE;
>> - unsigned IOCTL_KDSETLED = KDSETLED;
>> - unsigned IOCTL_KDSETMODE = KDSETMODE;
>> - unsigned IOCTL_KDSKBMODE = KDSKBMODE;
>> - unsigned IOCTL_KIOCSOUND = KIOCSOUND;
>> - unsigned IOCTL_PIO_SCRNMAP = PIO_SCRNMAP;
>> - unsigned IOCTL_SNDCTL_DSP_GETISPACE = SNDCTL_DSP_GETISPACE;
>> -
>> - const int si_SEGV_MAPERR = SEGV_MAPERR;
>> - const int si_SEGV_ACCERR = SEGV_ACCERR;
>> - const int unvis_valid = UNVIS_VALID;
>> - const int unvis_validpush = UNVIS_VALIDPUSH;
>> -} // namespace __sanitizer
>> +unsigned struct_midi_info_sz = sizeof(struct midi_info);
>> +unsigned struct_mtget_sz = sizeof(struct mtget);
>> +unsigned struct_mtop_sz = sizeof(struct mtop);
>> +unsigned struct_sbi_instrument_sz = sizeof(struct sbi_instrument);
>> +unsigned struct_seq_event_rec_sz = sizeof(struct seq_event_rec);
>> +unsigned struct_synth_info_sz = sizeof(struct synth_info);
>> +unsigned struct_audio_buf_info_sz = sizeof(struct audio_buf_info);
>> +unsigned struct_ppp_stats_sz = sizeof(struct ppp_stats);
>> +unsigned struct_sioc_sg_req_sz = sizeof(struct sioc_sg_req);
>> +unsigned struct_sioc_vif_req_sz = sizeof(struct sioc_vif_req);
>> +const unsigned long __sanitizer_bufsiz = BUFSIZ;
>> +
>> +const unsigned IOCTL_NOT_PRESENT = 0;
>> +
>> +unsigned IOCTL_FIOASYNC = FIOASYNC;
>> +unsigned IOCTL_FIOCLEX = FIOCLEX;
>> +unsigned IOCTL_FIOGETOWN = FIOGETOWN;
>> +unsigned IOCTL_FIONBIO = FIONBIO;
>> +unsigned IOCTL_FIONCLEX = FIONCLEX;
>> +unsigned IOCTL_FIOSETOWN = FIOSETOWN;
>> +unsigned IOCTL_SIOCADDMULTI = SIOCADDMULTI;
>> +unsigned IOCTL_SIOCATMARK = SIOCATMARK;
>> +unsigned IOCTL_SIOCDELMULTI = SIOCDELMULTI;
>> +unsigned IOCTL_SIOCGIFADDR = SIOCGIFADDR;
>> +unsigned IOCTL_SIOCGIFBRDADDR = SIOCGIFBRDADDR;
>> +unsigned IOCTL_SIOCGIFCONF = SIOCGIFCONF;
>> +unsigned IOCTL_SIOCGIFDSTADDR = SIOCGIFDSTADDR;
>> +unsigned IOCTL_SIOCGIFFLAGS = SIOCGIFFLAGS;
>> +unsigned IOCTL_SIOCGIFMETRIC = SIOCGIFMETRIC;
>> +unsigned IOCTL_SIOCGIFMTU = SIOCGIFMTU;
>> +unsigned IOCTL_SIOCGIFNETMASK = SIOCGIFNETMASK;
>> +unsigned IOCTL_SIOCGPGRP = SIOCGPGRP;
>> +unsigned IOCTL_SIOCSIFADDR = SIOCSIFADDR;
>> +unsigned IOCTL_SIOCSIFBRDADDR = SIOCSIFBRDADDR;
>> +unsigned IOCTL_SIOCSIFDSTADDR = SIOCSIFDSTADDR;
>> +unsigned IOCTL_SIOCSIFFLAGS = SIOCSIFFLAGS;
>> +unsigned IOCTL_SIOCSIFMETRIC = SIOCSIFMETRIC;
>> +unsigned IOCTL_SIOCSIFMTU = SIOCSIFMTU;
>> +unsigned IOCTL_SIOCSIFNETMASK = SIOCSIFNETMASK;
>> +unsigned IOCTL_SIOCSPGRP = SIOCSPGRP;
>> +unsigned IOCTL_TIOCCONS = TIOCCONS;
>> +unsigned IOCTL_TIOCEXCL = TIOCEXCL;
>> +unsigned IOCTL_TIOCGETD = TIOCGETD;
>> +unsigned IOCTL_TIOCGPGRP = TIOCGPGRP;
>> +unsigned IOCTL_TIOCGWINSZ = TIOCGWINSZ;
>> +unsigned IOCTL_TIOCMBIC = TIOCMBIC;
>> +unsigned IOCTL_TIOCMBIS = TIOCMBIS;
>> +unsigned IOCTL_TIOCMGET = TIOCMGET;
>> +unsigned IOCTL_TIOCMSET = TIOCMSET;
>> +unsigned IOCTL_TIOCNOTTY = TIOCNOTTY;
>> +unsigned IOCTL_TIOCNXCL = TIOCNXCL;
>> +unsigned IOCTL_TIOCOUTQ = TIOCOUTQ;
>> +unsigned IOCTL_TIOCPKT = TIOCPKT;
>> +unsigned IOCTL_TIOCSCTTY = TIOCSCTTY;
>> +unsigned IOCTL_TIOCSETD = TIOCSETD;
>> +unsigned IOCTL_TIOCSPGRP = TIOCSPGRP;
>> +unsigned IOCTL_TIOCSTI = TIOCSTI;
>> +unsigned IOCTL_TIOCSWINSZ = TIOCSWINSZ;
>> +unsigned IOCTL_SIOCGETSGCNT = SIOCGETSGCNT;
>> +unsigned IOCTL_SIOCGETVIFCNT = SIOCGETVIFCNT;
>> +unsigned IOCTL_MTIOCGET = MTIOCGET;
>> +unsigned IOCTL_MTIOCTOP = MTIOCTOP;
>> +unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE = SNDCTL_DSP_GETBLKSIZE;
>> +unsigned IOCTL_SNDCTL_DSP_GETFMTS = SNDCTL_DSP_GETFMTS;
>> +unsigned IOCTL_SNDCTL_DSP_NONBLOCK = SNDCTL_DSP_NONBLOCK;
>> +unsigned IOCTL_SNDCTL_DSP_POST = SNDCTL_DSP_POST;
>> +unsigned IOCTL_SNDCTL_DSP_RESET = SNDCTL_DSP_RESET;
>> +unsigned IOCTL_SNDCTL_DSP_SETFMT = SNDCTL_DSP_SETFMT;
>> +unsigned IOCTL_SNDCTL_DSP_SETFRAGMENT = SNDCTL_DSP_SETFRAGMENT;
>> +unsigned IOCTL_SNDCTL_DSP_SPEED = SNDCTL_DSP_SPEED;
>> +unsigned IOCTL_SNDCTL_DSP_STEREO = SNDCTL_DSP_STEREO;
>> +unsigned IOCTL_SNDCTL_DSP_SUBDIVIDE = SNDCTL_DSP_SUBDIVIDE;
>> +unsigned IOCTL_SNDCTL_DSP_SYNC = SNDCTL_DSP_SYNC;
>> +unsigned IOCTL_SNDCTL_FM_4OP_ENABLE = SNDCTL_FM_4OP_ENABLE;
>> +unsigned IOCTL_SNDCTL_FM_LOAD_INSTR = SNDCTL_FM_LOAD_INSTR;
>> +unsigned IOCTL_SNDCTL_MIDI_INFO = SNDCTL_MIDI_INFO;
>> +unsigned IOCTL_SNDCTL_MIDI_PRETIME = SNDCTL_MIDI_PRETIME;
>> +unsigned IOCTL_SNDCTL_SEQ_CTRLRATE = SNDCTL_SEQ_CTRLRATE;
>> +unsigned IOCTL_SNDCTL_SEQ_GETINCOUNT = SNDCTL_SEQ_GETINCOUNT;
>> +unsigned IOCTL_SNDCTL_SEQ_GETOUTCOUNT = SNDCTL_SEQ_GETOUTCOUNT;
>> +unsigned IOCTL_SNDCTL_SEQ_NRMIDIS = SNDCTL_SEQ_NRMIDIS;
>> +unsigned IOCTL_SNDCTL_SEQ_NRSYNTHS = SNDCTL_SEQ_NRSYNTHS;
>> +unsigned IOCTL_SNDCTL_SEQ_OUTOFBAND = SNDCTL_SEQ_OUTOFBAND;
>> +unsigned IOCTL_SNDCTL_SEQ_PANIC = SNDCTL_SEQ_PANIC;
>> +unsigned IOCTL_SNDCTL_SEQ_PERCMODE = SNDCTL_SEQ_PERCMODE;
>> +unsigned IOCTL_SNDCTL_SEQ_RESET = SNDCTL_SEQ_RESET;
>> +unsigned IOCTL_SNDCTL_SEQ_RESETSAMPLES = SNDCTL_SEQ_RESETSAMPLES;
>> +unsigned IOCTL_SNDCTL_SEQ_SYNC = SNDCTL_SEQ_SYNC;
>> +unsigned IOCTL_SNDCTL_SEQ_TESTMIDI = SNDCTL_SEQ_TESTMIDI;
>> +unsigned IOCTL_SNDCTL_SEQ_THRESHOLD = SNDCTL_SEQ_THRESHOLD;
>> +unsigned IOCTL_SNDCTL_SYNTH_INFO = SNDCTL_SYNTH_INFO;
>> +unsigned IOCTL_SNDCTL_SYNTH_MEMAVL = SNDCTL_SYNTH_MEMAVL;
>> +unsigned IOCTL_SNDCTL_TMR_CONTINUE = SNDCTL_TMR_CONTINUE;
>> +unsigned IOCTL_SNDCTL_TMR_METRONOME = SNDCTL_TMR_METRONOME;
>> +unsigned IOCTL_SNDCTL_TMR_SELECT = SNDCTL_TMR_SELECT;
>> +unsigned IOCTL_SNDCTL_TMR_SOURCE = SNDCTL_TMR_SOURCE;
>> +unsigned IOCTL_SNDCTL_TMR_START = SNDCTL_TMR_START;
>> +unsigned IOCTL_SNDCTL_TMR_STOP = SNDCTL_TMR_STOP;
>> +unsigned IOCTL_SNDCTL_TMR_TEMPO = SNDCTL_TMR_TEMPO;
>> +unsigned IOCTL_SNDCTL_TMR_TIMEBASE = SNDCTL_TMR_TIMEBASE;
>> +unsigned IOCTL_SOUND_MIXER_READ_ALTPCM = SOUND_MIXER_READ_ALTPCM;
>> +unsigned IOCTL_SOUND_MIXER_READ_BASS = SOUND_MIXER_READ_BASS;
>> +unsigned IOCTL_SOUND_MIXER_READ_CAPS = SOUND_MIXER_READ_CAPS;
>> +unsigned IOCTL_SOUND_MIXER_READ_CD = SOUND_MIXER_READ_CD;
>> +unsigned IOCTL_SOUND_MIXER_READ_DEVMASK = SOUND_MIXER_READ_DEVMASK;
>> +unsigned IOCTL_SOUND_MIXER_READ_ENHANCE = SOUND_MIXER_READ_ENHANCE;
>> +unsigned IOCTL_SOUND_MIXER_READ_IGAIN = SOUND_MIXER_READ_IGAIN;
>> +unsigned IOCTL_SOUND_MIXER_READ_IMIX = SOUND_MIXER_READ_IMIX;
>> +unsigned IOCTL_SOUND_MIXER_READ_LINE = SOUND_MIXER_READ_LINE;
>> +unsigned IOCTL_SOUND_MIXER_READ_LINE1 = SOUND_MIXER_READ_LINE1;
>> +unsigned IOCTL_SOUND_MIXER_READ_LINE2 = SOUND_MIXER_READ_LINE2;
>> +unsigned IOCTL_SOUND_MIXER_READ_LINE3 = SOUND_MIXER_READ_LINE3;
>> +unsigned IOCTL_SOUND_MIXER_READ_LOUD = SOUND_MIXER_READ_LOUD;
>> +unsigned IOCTL_SOUND_MIXER_READ_MIC = SOUND_MIXER_READ_MIC;
>> +unsigned IOCTL_SOUND_MIXER_READ_MUTE = SOUND_MIXER_READ_MUTE;
>> +unsigned IOCTL_SOUND_MIXER_READ_OGAIN = SOUND_MIXER_READ_OGAIN;
>> +unsigned IOCTL_SOUND_MIXER_READ_PCM = SOUND_MIXER_READ_PCM;
>> +unsigned IOCTL_SOUND_MIXER_READ_RECLEV = SOUND_MIXER_READ_RECLEV;
>> +unsigned IOCTL_SOUND_MIXER_READ_RECMASK = SOUND_MIXER_READ_RECMASK;
>> +unsigned IOCTL_SOUND_MIXER_READ_RECSRC = SOUND_MIXER_READ_RECSRC;
>> +unsigned IOCTL_SOUND_MIXER_READ_SPEAKER = SOUND_MIXER_READ_SPEAKER;
>> +unsigned IOCTL_SOUND_MIXER_READ_STEREODEVS =
>> SOUND_MIXER_READ_STEREODEVS;
>> +unsigned IOCTL_SOUND_MIXER_READ_SYNTH = SOUND_MIXER_READ_SYNTH;
>> +unsigned IOCTL_SOUND_MIXER_READ_TREBLE = SOUND_MIXER_READ_TREBLE;
>> +unsigned IOCTL_SOUND_MIXER_READ_VOLUME = SOUND_MIXER_READ_VOLUME;
>> +unsigned IOCTL_SOUND_MIXER_WRITE_ALTPCM = SOUND_MIXER_WRITE_ALTPCM;
>> +unsigned IOCTL_SOUND_MIXER_WRITE_BASS = SOUND_MIXER_WRITE_BASS;
>> +unsigned IOCTL_SOUND_MIXER_WRITE_CD = SOUND_MIXER_WRITE_CD;
>> +unsigned IOCTL_SOUND_MIXER_WRITE_ENHANCE = SOUND_MIXER_WRITE_ENHANCE;
>> +unsigned IOCTL_SOUND_MIXER_WRITE_IGAIN = SOUND_MIXER_WRITE_IGAIN;
>> +unsigned IOCTL_SOUND_MIXER_WRITE_IMIX = SOUND_MIXER_WRITE_IMIX;
>> +unsigned IOCTL_SOUND_MIXER_WRITE_LINE = SOUND_MIXER_WRITE_LINE;
>> +unsigned IOCTL_SOUND_MIXER_WRITE_LINE1 = SOUND_MIXER_WRITE_LINE1;
>> +unsigned IOCTL_SOUND_MIXER_WRITE_LINE2 = SOUND_MIXER_WRITE_LINE2;
>> +unsigned IOCTL_SOUND_MIXER_WRITE_LINE3 = SOUND_MIXER_WRITE_LINE3;
>> +unsigned IOCTL_SOUND_MIXER_WRITE_LOUD = SOUND_MIXER_WRITE_LOUD;
>> +unsigned IOCTL_SOUND_MIXER_WRITE_MIC = SOUND_MIXER_WRITE_MIC;
>> +unsigned IOCTL_SOUND_MIXER_WRITE_MUTE = SOUND_MIXER_WRITE_MUTE;
>> +unsigned IOCTL_SOUND_MIXER_WRITE_OGAIN = SOUND_MIXER_WRITE_OGAIN;
>> +unsigned IOCTL_SOUND_MIXER_WRITE_PCM = SOUND_MIXER_WRITE_PCM;
>> +unsigned IOCTL_SOUND_MIXER_WRITE_RECLEV = SOUND_MIXER_WRITE_RECLEV;
>> +unsigned IOCTL_SOUND_MIXER_WRITE_RECSRC = SOUND_MIXER_WRITE_RECSRC;
>> +unsigned IOCTL_SOUND_MIXER_WRITE_SPEAKER = SOUND_MIXER_WRITE_SPEAKER;
>> +unsigned IOCTL_SOUND_MIXER_WRITE_SYNTH = SOUND_MIXER_WRITE_SYNTH;
>> +unsigned IOCTL_SOUND_MIXER_WRITE_TREBLE = SOUND_MIXER_WRITE_TREBLE;
>> +unsigned IOCTL_SOUND_MIXER_WRITE_VOLUME = SOUND_MIXER_WRITE_VOLUME;
>> +unsigned IOCTL_VT_ACTIVATE = VT_ACTIVATE;
>> +unsigned IOCTL_VT_GETMODE = VT_GETMODE;
>> +unsigned IOCTL_VT_OPENQRY = VT_OPENQRY;
>> +unsigned IOCTL_VT_RELDISP = VT_RELDISP;
>> +unsigned IOCTL_VT_SETMODE = VT_SETMODE;
>> +unsigned IOCTL_VT_WAITACTIVE = VT_WAITACTIVE;
>> +unsigned IOCTL_GIO_SCRNMAP = GIO_SCRNMAP;
>> +unsigned IOCTL_KDDISABIO = KDDISABIO;
>> +unsigned IOCTL_KDENABIO = KDENABIO;
>> +unsigned IOCTL_KDGETLED = KDGETLED;
>> +unsigned IOCTL_KDGETMODE = KDGETMODE;
>> +unsigned IOCTL_KDGKBMODE = KDGKBMODE;
>> +unsigned IOCTL_KDGKBTYPE = KDGKBTYPE;
>> +unsigned IOCTL_KDMKTONE = KDMKTONE;
>> +unsigned IOCTL_KDSETLED = KDSETLED;
>> +unsigned IOCTL_KDSETMODE = KDSETMODE;
>> +unsigned IOCTL_KDSKBMODE = KDSKBMODE;
>> +unsigned IOCTL_KIOCSOUND = KIOCSOUND;
>> +unsigned IOCTL_PIO_SCRNMAP = PIO_SCRNMAP;
>> +unsigned IOCTL_SNDCTL_DSP_GETISPACE = SNDCTL_DSP_GETISPACE;
>> +
>> +const int si_SEGV_MAPERR = SEGV_MAPERR;
>> +const int si_SEGV_ACCERR = SEGV_ACCERR;
>> +const int unvis_valid = UNVIS_VALID;
>> +const int unvis_validpush = UNVIS_VALIDPUSH;
>> +} // namespace __sanitizer
>>
>> using namespace __sanitizer;
>>
>> diff --git
>> a/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.h
>> b/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.h
>> index 71cf5b9c357..5e0ca9c7d78 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.h
>> +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.h
>> @@ -18,18 +18,17 @@
>>
>> #include "sanitizer_internal_defs.h"
>> #include "sanitizer_platform.h"
>> -
>> #include "sanitizer_platform_limits_posix.h"
>>
>> -// FreeBSD's dlopen() returns a pointer to an Obj_Entry structure that
>> -// incorporates the map structure.
>> -# define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \
>> - ((link_map*)((handle) == nullptr ? nullptr : ((char*)(handle) +
>> 560)))
>> // Get sys/_types.h, because that tells us whether 64-bit inodes are
>> // used in struct dirent below.
>> #include <sys/_types.h>
>>
>> namespace __sanitizer {
>> +void *__sanitizer_get_link_map_by_dlopen_handle(void *handle);
>> +#define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \
>> + (link_map *)__sanitizer_get_link_map_by_dlopen_handle(handle)
>> +
>> extern unsigned struct_utsname_sz;
>> extern unsigned struct_stat_sz;
>> #if defined(__powerpc64__)
>> @@ -53,6 +52,7 @@ extern unsigned struct_timezone_sz;
>> extern unsigned struct_tms_sz;
>> extern unsigned struct_itimerspec_sz;
>> extern unsigned struct_sigevent_sz;
>> +extern unsigned struct_stack_t_sz;
>> extern unsigned struct_sched_param_sz;
>> extern unsigned struct_statfs64_sz;
>> extern unsigned struct_statfs_sz;
>> @@ -147,7 +147,7 @@ struct __sanitizer_ifaddrs {
>> unsigned int ifa_flags;
>> void *ifa_addr; // (struct sockaddr *)
>> void *ifa_netmask; // (struct sockaddr *)
>> -# undef ifa_dstaddr
>> +#undef ifa_dstaddr
>> void *ifa_dstaddr; // (struct sockaddr *)
>> void *ifa_data;
>> };
>> @@ -630,27 +630,27 @@ extern unsigned struct_cap_rights_sz;
>>
>> extern unsigned struct_fstab_sz;
>> extern unsigned struct_StringList_sz;
>> -} // namespace __sanitizer
>> +} // 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) == \
>> +#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)
>> == \
>> +#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))
>>
>> #define SIGACTION_SYMNAME sigaction
>>
>> #endif
>>
>> -#endif // SANITIZER_FREEBSD
>> +#endif // SANITIZER_FREEBSD
>> diff --git
>> a/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cpp
>> b/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cpp
>> index f22f5039128..c51327e1269 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cpp
>> @@ -26,12 +26,9 @@
>>
>> // 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. Beware that with <sys/stat.h>,
>> struct stat
>> -// takes the form of struct stat64 on 32-bit platforms if
>> _FILE_OFFSET_BITS=64.
>> -// Also, for some platforms (e.g. mips) there are additional members
>> in the
>> -// <sys/stat.h> struct stat:s.
>> +// fine with newer headers, too.
>> #include <linux/posix_types.h>
>> -#if defined(__x86_64__)
>> +#if defined(__x86_64__) || defined(__mips__)
>> #include <sys/stat.h>
>> #else
>> #define ino_t __kernel_ino_t
>> diff --git
>> a/libsanitizer/sanitizer_common/sanitizer_platform_limits_netbsd.cpp
>> b/libsanitizer/sanitizer_common/sanitizer_platform_limits_netbsd.cpp
>> index f01de6c995e..25da334b63f 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_netbsd.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_netbsd.cpp
>> @@ -17,6 +17,7 @@
>>
>> #define _KMEMUSER
>> #define RAY_DO_SIGLEV
>> +#define __LEGACY_PT_LWPINFO
>>
>> // clang-format off
>> #include <sys/param.h>
>> @@ -71,6 +72,15 @@
>> #include <sys/msg.h>
>> #include <sys/mtio.h>
>> #include <sys/ptrace.h>
>> +
>> +// Compat for NetBSD < 9.99.30.
>> +#ifndef PT_LWPSTATUS
>> +#define PT_LWPSTATUS 24
>> +#endif
>> +#ifndef PT_LWPNEXT
>> +#define PT_LWPNEXT 25
>> +#endif
>> +
>> #include <sys/resource.h>
>> #include <sys/sem.h>
>> #include <sys/sha1.h>
>> @@ -109,7 +119,12 @@
>> #include <dev/dmover/dmover_io.h>
>> #include <dev/dtv/dtvio_demux.h>
>> #include <dev/dtv/dtvio_frontend.h>
>> +#if !__NetBSD_Prereq__(9, 99, 26)
>> #include <dev/filemon/filemon.h>
>> +#else
>> +#define FILEMON_SET_FD _IOWR('S', 1, int)
>> +#define FILEMON_SET_PID _IOWR('S', 2, pid_t)
>> +#endif
>> #include <dev/hdaudio/hdaudioio.h>
>> #include <dev/hdmicec/hdmicecio.h>
>> #include <dev/hpc/hpcfbio.h>
>> @@ -146,12 +161,121 @@
>> #include <net/slip.h>
>> #include <netbt/hci.h>
>> #include <netinet/ip_compat.h>
>> +#if __has_include(<netinet/ip_fil.h>)
>> #include <netinet/ip_fil.h>
>> #include <netinet/ip_nat.h>
>> #include <netinet/ip_proxy.h>
>> +#else
>> +/* Fallback for MKIPFILTER=no */
>> +
>> +typedef struct ap_control {
>> + char apc_label[16];
>> + char apc_config[16];
>> + unsigned char apc_p;
>> + unsigned long apc_cmd;
>> + unsigned long apc_arg;
>> + void *apc_data;
>> + size_t apc_dsize;
>> +} ap_ctl_t;
>> +
>> +typedef struct ipftq {
>> + ipfmutex_t ifq_lock;
>> + unsigned int ifq_ttl;
>> + void *ifq_head;
>> + void **ifq_tail;
>> + void *ifq_next;
>> + void **ifq_pnext;
>> + int ifq_ref;
>> + unsigned int ifq_flags;
>> +} ipftq_t;
>> +
>> +typedef struct ipfobj {
>> + uint32_t ipfo_rev;
>> + uint32_t ipfo_size;
>> + void *ipfo_ptr;
>> + int ipfo_type;
>> + int ipfo_offset;
>> + int ipfo_retval;
>> + unsigned char ipfo_xxxpad[28];
>> +} ipfobj_t;
>> +
>> +#define SIOCADNAT _IOW('r', 60, struct ipfobj)
>> +#define SIOCRMNAT _IOW('r', 61, struct ipfobj)
>> +#define SIOCGNATS _IOWR('r', 62, struct ipfobj)
>> +#define SIOCGNATL _IOWR('r', 63, struct ipfobj)
>> +#define SIOCPURGENAT _IOWR('r', 100, struct ipfobj)
>> +#endif
>> #include <netinet6/in6_var.h>
>> #include <netinet6/nd6.h>
>> +#if !__NetBSD_Prereq__(9, 99, 51)
>> #include <netsmb/smb_dev.h>
>> +#else
>> +struct smbioc_flags {
>> + int ioc_level;
>> + int ioc_mask;
>> + int ioc_flags;
>> +};
>> +struct smbioc_oshare {
>> + int ioc_opt;
>> + int ioc_stype;
>> + char ioc_share[129];
>> + char ioc_password[129];
>> + uid_t ioc_owner;
>> + gid_t ioc_group;
>> + mode_t ioc_mode;
>> + mode_t ioc_rights;
>> +};
>> +struct smbioc_ossn {
>> + int ioc_opt;
>> + uint32_t ioc_svlen;
>> + struct sockaddr *ioc_server;
>> + uint32_t ioc_lolen;
>> + struct sockaddr *ioc_local;
>> + char ioc_srvname[16];
>> + int ioc_timeout;
>> + int ioc_retrycount;
>> + char ioc_localcs[16];
>> + char ioc_servercs[16];
>> + char ioc_user[129];
>> + char ioc_workgroup[129];
>> + char ioc_password[129];
>> + uid_t ioc_owner;
>> + gid_t ioc_group;
>> + mode_t ioc_mode;
>> + mode_t ioc_rights;
>> +};
>> +struct smbioc_lookup {
>> + int ioc_level;
>> + int ioc_flags;
>> + struct smbioc_ossn ioc_ssn;
>> + struct smbioc_oshare ioc_sh;
>> +};
>> +struct smbioc_rq {
>> + u_char ioc_cmd;
>> + u_char ioc_twc;
>> + void *ioc_twords;
>> + u_short ioc_tbc;
>> + void *ioc_tbytes;
>> + int ioc_rpbufsz;
>> + char *ioc_rpbuf;
>> + u_char ioc_rwc;
>> + u_short ioc_rbc;
>> +};
>> +struct smbioc_rw {
>> + u_int16_t ioc_fh;
>> + char *ioc_base;
>> + off_t ioc_offset;
>> + int ioc_cnt;
>> +};
>> +#define SMBIOC_OPENSESSION _IOW('n', 100, struct smbioc_ossn)
>> +#define SMBIOC_OPENSHARE _IOW('n', 101, struct smbioc_oshare)
>> +#define SMBIOC_REQUEST _IOWR('n', 102, struct smbioc_rq)
>> +#define SMBIOC_T2RQ _IOWR('n', 103, struct smbioc_t2rq)
>> +#define SMBIOC_SETFLAGS _IOW('n', 104, struct smbioc_flags)
>> +#define SMBIOC_LOOKUP _IOW('n', 106, struct smbioc_lookup)
>> +#define SMBIOC_READ _IOWR('n', 107, struct smbioc_rw)
>> +#define SMBIOC_WRITE _IOWR('n', 108, struct smbioc_rw)
>> +#endif
>> #include <dev/biovar.h>
>> #include <dev/bluetooth/btdev.h>
>> #include <dev/bluetooth/btsco.h>
>> @@ -175,7 +299,21 @@
>> #include <dev/sun/vuid_event.h>
>> #include <dev/tc/sticio.h>
>> #include <dev/usb/ukyopon.h>
>> +#if !__NetBSD_Prereq__(9, 99, 44)
>> #include <dev/usb/urio.h>
>> +#else
>> +struct urio_command {
>> + unsigned short length;
>> + int request;
>> + int requesttype;
>> + int value;
>> + int index;
>> + void *buffer;
>> + int timeout;
>> +};
>> +#define URIO_SEND_COMMAND _IOWR('U', 200, struct urio_command)
>> +#define URIO_RECV_COMMAND _IOWR('U', 201, struct urio_command)
>> +#endif
>> #include <dev/usb/usb.h>
>> #include <dev/usb/utoppy.h>
>> #include <dev/vme/xio.h>
>> @@ -184,6 +322,7 @@
>> #include <dev/wscons/wsdisplay_usl_io.h>
>> #include <fs/autofs/autofs_ioctl.h>
>> #include <dirent.h>
>> +#include <dlfcn.h>
>> #include <glob.h>
>> #include <grp.h>
>> #include <ifaddrs.h>
>> @@ -229,9 +368,15 @@
>>
>> // Include these after system headers to avoid name clashes and
>> ambiguities.
>> #include "sanitizer_internal_defs.h"
>> +#include "sanitizer_libc.h"
>> #include "sanitizer_platform_limits_netbsd.h"
>>
>> namespace __sanitizer {
>> +void *__sanitizer_get_link_map_by_dlopen_handle(void* handle) {
>> + void *p = nullptr;
>> + return internal_dlinfo(handle, RTLD_DI_LINKMAP, &p) == 0 ? p :
>> nullptr;
>> +}
>> +
>> unsigned struct_utsname_sz = sizeof(struct utsname);
>> unsigned struct_stat_sz = sizeof(struct stat);
>> unsigned struct_rusage_sz = sizeof(struct rusage);
>> @@ -240,6 +385,7 @@ unsigned struct_passwd_sz = sizeof(struct passwd);
>> unsigned struct_group_sz = sizeof(struct group);
>> unsigned siginfo_t_sz = sizeof(siginfo_t);
>> unsigned struct_sigaction_sz = sizeof(struct sigaction);
>> +unsigned struct_stack_t_sz = sizeof(stack_t);
>> unsigned struct_itimerval_sz = sizeof(struct itimerval);
>> unsigned pthread_t_sz = sizeof(pthread_t);
>> unsigned pthread_mutex_t_sz = sizeof(pthread_mutex_t);
>> @@ -287,6 +433,8 @@ int ptrace_pt_get_event_mask = PT_GET_EVENT_MASK;
>> int ptrace_pt_get_process_state = PT_GET_PROCESS_STATE;
>> int ptrace_pt_set_siginfo = PT_SET_SIGINFO;
>> int ptrace_pt_get_siginfo = PT_GET_SIGINFO;
>> +int ptrace_pt_lwpstatus = PT_LWPSTATUS;
>> +int ptrace_pt_lwpnext = PT_LWPNEXT;
>> int ptrace_piod_read_d = PIOD_READ_D;
>> int ptrace_piod_write_d = PIOD_WRITE_D;
>> int ptrace_piod_read_i = PIOD_READ_I;
>> @@ -319,6 +467,8 @@ int ptrace_pt_getdbregs = -1;
>>
>> unsigned struct_ptrace_ptrace_io_desc_struct_sz = sizeof(struct
>> ptrace_io_desc);
>> unsigned struct_ptrace_ptrace_lwpinfo_struct_sz = sizeof(struct
>> ptrace_lwpinfo);
>> +unsigned struct_ptrace_ptrace_lwpstatus_struct_sz =
>> + sizeof(struct __sanitizer_ptrace_lwpstatus);
>> unsigned struct_ptrace_ptrace_event_struct_sz =
>> sizeof(ptrace_event_t);
>> unsigned struct_ptrace_ptrace_siginfo_struct_sz =
>> sizeof(ptrace_siginfo_t);
>>
>> @@ -698,6 +848,7 @@ unsigned struct_nvmm_ioc_machine_configure_sz =
>> sizeof(nvmm_ioc_machine_configure);
>> unsigned struct_nvmm_ioc_vcpu_create_sz =
>> sizeof(nvmm_ioc_vcpu_create);
>> unsigned struct_nvmm_ioc_vcpu_destroy_sz =
>> sizeof(nvmm_ioc_vcpu_destroy);
>> +unsigned struct_nvmm_ioc_vcpu_configure_sz =
>> sizeof(nvmm_ioc_vcpu_configure);
>> unsigned struct_nvmm_ioc_vcpu_setstate_sz =
>> sizeof(nvmm_ioc_vcpu_destroy);
>> unsigned struct_nvmm_ioc_vcpu_getstate_sz =
>> sizeof(nvmm_ioc_vcpu_getstate);
>> unsigned struct_nvmm_ioc_vcpu_inject_sz =
>> sizeof(nvmm_ioc_vcpu_inject);
>> @@ -1458,6 +1609,7 @@ unsigned IOCTL_NVMM_IOC_MACHINE_DESTROY =
>> NVMM_IOC_MACHINE_DESTROY;
>> unsigned IOCTL_NVMM_IOC_MACHINE_CONFIGURE =
>> NVMM_IOC_MACHINE_CONFIGURE;
>> unsigned IOCTL_NVMM_IOC_VCPU_CREATE = NVMM_IOC_VCPU_CREATE;
>> unsigned IOCTL_NVMM_IOC_VCPU_DESTROY = NVMM_IOC_VCPU_DESTROY;
>> +unsigned IOCTL_NVMM_IOC_VCPU_CONFIGURE = NVMM_IOC_VCPU_CONFIGURE;
>> unsigned IOCTL_NVMM_IOC_VCPU_SETSTATE = NVMM_IOC_VCPU_SETSTATE;
>> unsigned IOCTL_NVMM_IOC_VCPU_GETSTATE = NVMM_IOC_VCPU_GETSTATE;
>> unsigned IOCTL_NVMM_IOC_VCPU_INJECT = NVMM_IOC_VCPU_INJECT;
>> @@ -1534,6 +1686,7 @@ unsigned IOCTL_IOC_NPF_STATS = IOC_NPF_STATS;
>> unsigned IOCTL_IOC_NPF_SAVE = IOC_NPF_SAVE;
>> unsigned IOCTL_IOC_NPF_RULE = IOC_NPF_RULE;
>> unsigned IOCTL_IOC_NPF_CONN_LOOKUP = IOC_NPF_CONN_LOOKUP;
>> +unsigned IOCTL_IOC_NPF_TABLE_REPLACE = IOC_NPF_TABLE_REPLACE;
>> unsigned IOCTL_PPPOESETPARMS = PPPOESETPARMS;
>> unsigned IOCTL_PPPOEGETPARMS = PPPOEGETPARMS;
>> unsigned IOCTL_PPPOEGETSESSION = PPPOEGETSESSION;
>> @@ -2392,4 +2545,42 @@ CHECK_SIZE_AND_OFFSET(modctl_load_t, ml_flags);
>> CHECK_SIZE_AND_OFFSET(modctl_load_t, ml_props);
>> CHECK_SIZE_AND_OFFSET(modctl_load_t, ml_propslen);
>>
>> +// Compat with 9.0
>> +struct statvfs90 {
>> + unsigned long f_flag;
>> + unsigned long f_bsize;
>> + unsigned long f_frsize;
>> + unsigned long f_iosize;
>> +
>> + u64 f_blocks;
>> + u64 f_bfree;
>> + u64 f_bavail;
>> + u64 f_bresvd;
>> +
>> + u64 f_files;
>> + u64 f_ffree;
>> + u64 f_favail;
>> + u64 f_fresvd;
>> +
>> + u64 f_syncreads;
>> + u64 f_syncwrites;
>> +
>> + u64 f_asyncreads;
>> + u64 f_asyncwrites;
>> +
>> + struct {
>> + s32 __fsid_val[2];
>> + } f_fsidx;
>> + unsigned long f_fsid;
>> + unsigned long f_namemax;
>> + u32 f_owner;
>> +
>> + u32 f_spare[4];
>> +
>> + char f_fstypename[32];
>> + char f_mntonname[32];
>> + char f_mntfromname[32];
>> +};
>> +unsigned struct_statvfs90_sz = sizeof(struct statvfs90);
>> +
>> #endif // SANITIZER_NETBSD
>> diff --git
>> a/libsanitizer/sanitizer_common/sanitizer_platform_limits_netbsd.h
>> b/libsanitizer/sanitizer_common/sanitizer_platform_limits_netbsd.h
>> index 419d830c69e..d80280d9bf8 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_netbsd.h
>> +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_netbsd.h
>> @@ -19,18 +19,11 @@
>> #include "sanitizer_internal_defs.h"
>> #include "sanitizer_platform.h"
>>
>> -#define _GET_LINK_MAP_BY_DLOPEN_HANDLE(handle, shift) \
>> - ((link_map *)((handle) == nullptr ? nullptr : ((char *)(handle) +
>> (shift))))
>> -
>> -#if defined(__x86_64__)
>> -#define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \
>> - _GET_LINK_MAP_BY_DLOPEN_HANDLE(handle, 264)
>> -#elif defined(__i386__)
>> -#define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \
>> - _GET_LINK_MAP_BY_DLOPEN_HANDLE(handle, 136)
>> -#endif
>> -
>> namespace __sanitizer {
>> +void *__sanitizer_get_link_map_by_dlopen_handle(void *handle);
>> +# define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \
>> + (link_map *)__sanitizer_get_link_map_by_dlopen_handle(handle)
>> +
>> extern unsigned struct_utsname_sz;
>> extern unsigned struct_stat_sz;
>> extern unsigned struct_rusage_sz;
>> @@ -48,6 +41,7 @@ extern unsigned struct_timezone_sz;
>> extern unsigned struct_tms_sz;
>> extern unsigned struct_itimerspec_sz;
>> extern unsigned struct_sigevent_sz;
>> +extern unsigned struct_stack_t_sz;
>> extern unsigned struct_sched_param_sz;
>> extern unsigned struct_statfs_sz;
>> extern unsigned struct_sockaddr_sz;
>> @@ -412,6 +406,8 @@ extern int ptrace_pt_get_event_mask;
>> extern int ptrace_pt_get_process_state;
>> extern int ptrace_pt_set_siginfo;
>> extern int ptrace_pt_get_siginfo;
>> +extern int ptrace_pt_lwpstatus;
>> +extern int ptrace_pt_lwpnext;
>> extern int ptrace_piod_read_d;
>> extern int ptrace_piod_write_d;
>> extern int ptrace_piod_read_i;
>> @@ -436,8 +432,17 @@ struct __sanitizer_ptrace_lwpinfo {
>> int pl_event;
>> };
>>
>> +struct __sanitizer_ptrace_lwpstatus {
>> + __sanitizer_lwpid_t pl_lwpid;
>> + __sanitizer_sigset_t pl_sigpend;
>> + __sanitizer_sigset_t pl_sigmask;
>> + char pl_name[20];
>> + void *pl_private;
>> +};
>> +
>> extern unsigned struct_ptrace_ptrace_io_desc_struct_sz;
>> extern unsigned struct_ptrace_ptrace_lwpinfo_struct_sz;
>> +extern unsigned struct_ptrace_ptrace_lwpstatus_struct_sz;
>> extern unsigned struct_ptrace_ptrace_event_struct_sz;
>> extern unsigned struct_ptrace_ptrace_siginfo_struct_sz;
>>
>> @@ -862,6 +867,7 @@ extern unsigned struct_nvmm_ioc_machine_destroy_sz;
>> extern unsigned struct_nvmm_ioc_machine_configure_sz;
>> extern unsigned struct_nvmm_ioc_vcpu_create_sz;
>> extern unsigned struct_nvmm_ioc_vcpu_destroy_sz;
>> +extern unsigned struct_nvmm_ioc_vcpu_configure_sz;
>> extern unsigned struct_nvmm_ioc_vcpu_setstate_sz;
>> extern unsigned struct_nvmm_ioc_vcpu_getstate_sz;
>> extern unsigned struct_nvmm_ioc_vcpu_inject_sz;
>> @@ -1611,6 +1617,7 @@ extern unsigned IOCTL_NVMM_IOC_MACHINE_DESTROY;
>> extern unsigned IOCTL_NVMM_IOC_MACHINE_CONFIGURE;
>> extern unsigned IOCTL_NVMM_IOC_VCPU_CREATE;
>> extern unsigned IOCTL_NVMM_IOC_VCPU_DESTROY;
>> +extern unsigned IOCTL_NVMM_IOC_VCPU_CONFIGURE;
>> extern unsigned IOCTL_NVMM_IOC_VCPU_SETSTATE;
>> extern unsigned IOCTL_NVMM_IOC_VCPU_GETSTATE;
>> extern unsigned IOCTL_NVMM_IOC_VCPU_INJECT;
>> @@ -1685,6 +1692,7 @@ extern unsigned IOCTL_IOC_NPF_STATS;
>> extern unsigned IOCTL_IOC_NPF_SAVE;
>> extern unsigned IOCTL_IOC_NPF_RULE;
>> extern unsigned IOCTL_IOC_NPF_CONN_LOOKUP;
>> +extern unsigned IOCTL_IOC_NPF_TABLE_REPLACE;
>> extern unsigned IOCTL_PPPOESETPARMS;
>> extern unsigned IOCTL_PPPOEGETPARMS;
>> extern unsigned IOCTL_PPPOEGETSESSION;
>> @@ -2406,6 +2414,9 @@ struct __sanitizer_cdbw {
>>
>> #define SIGACTION_SYMNAME __sigaction14
>>
>> +// Compat with 9.0
>> +extern unsigned struct_statvfs90_sz;
>> +
>> #endif // SANITIZER_NETBSD
>>
>> #endif
>> diff --git
>> a/libsanitizer/sanitizer_common/sanitizer_platform_limits_openbsd.cpp
>> b/libsanitizer/sanitizer_common/sanitizer_platform_limits_openbsd.cpp
>> index 12515626ce5..1420ecbfa56 100644
>> ---
>> a/libsanitizer/sanitizer_common/sanitizer_platform_limits_openbsd.cpp
>> +++
>> b/libsanitizer/sanitizer_common/sanitizer_platform_limits_openbsd.cpp
>> @@ -72,6 +72,7 @@ unsigned struct_passwd_sz = sizeof(struct passwd);
>> unsigned struct_group_sz = sizeof(struct group);
>> unsigned siginfo_t_sz = sizeof(siginfo_t);
>> unsigned struct_sigaction_sz = sizeof(struct sigaction);
>> +unsigned struct_stack_t_sz = sizeof(stack_t);
>> unsigned struct_itimerval_sz = sizeof(struct itimerval);
>> unsigned pthread_t_sz = sizeof(pthread_t);
>> unsigned pthread_mutex_t_sz = sizeof(pthread_mutex_t);
>> diff --git
>> a/libsanitizer/sanitizer_common/sanitizer_platform_limits_openbsd.h
>> b/libsanitizer/sanitizer_common/sanitizer_platform_limits_openbsd.h
>> index 6d8b062716b..8a194872360 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_openbsd.h
>> +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_openbsd.h
>> @@ -50,6 +50,7 @@ extern unsigned struct_timezone_sz;
>> extern unsigned struct_tms_sz;
>> extern unsigned struct_itimerspec_sz;
>> extern unsigned struct_sigevent_sz;
>> +extern unsigned struct_stack_t_sz;
>> extern unsigned struct_statfs_sz;
>> extern unsigned struct_sockaddr_sz;
>>
>> diff --git
>> a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp
>> b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp
>> index aa845df4dde..e71515f12e9 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp
>> @@ -179,6 +179,7 @@ namespace __sanitizer {
>> unsigned struct_group_sz = sizeof(struct group);
>> unsigned siginfo_t_sz = sizeof(siginfo_t);
>> unsigned struct_sigaction_sz = sizeof(struct sigaction);
>> + unsigned struct_stack_t_sz = sizeof(stack_t);
>> unsigned struct_itimerval_sz = sizeof(struct itimerval);
>> unsigned pthread_t_sz = sizeof(pthread_t);
>> unsigned pthread_mutex_t_sz = sizeof(pthread_mutex_t);
>> diff --git
>> a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h
>> b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h
>> index d82fd5e4005..f6c8a1450a9 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h
>> +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h
>> @@ -47,6 +47,7 @@ extern unsigned struct_timezone_sz;
>> extern unsigned struct_tms_sz;
>> extern unsigned struct_itimerspec_sz;
>> extern unsigned struct_sigevent_sz;
>> +extern unsigned struct_stack_t_sz;
>> extern unsigned struct_sched_param_sz;
>> extern unsigned struct_statfs64_sz;
>> extern unsigned struct_regex_sz;
>> @@ -82,7 +83,7 @@ const unsigned struct_kernel_stat64_sz = 104;
>> #elif defined(__mips__)
>> const unsigned struct_kernel_stat_sz = SANITIZER_ANDROID
>> ?
>> FIRST_32_SECOND_64(104, 128)
>> - : FIRST_32_SECOND_64(144,
>> 216);
>> + : FIRST_32_SECOND_64(160,
>> 216);
>> const unsigned struct_kernel_stat64_sz = 104;
>> #elif defined(__s390__) && !defined(__s390x__)
>> const unsigned struct_kernel_stat_sz = 64;
>> diff --git
>> a/libsanitizer/sanitizer_common/sanitizer_platform_limits_solaris.cpp
>> b/libsanitizer/sanitizer_common/sanitizer_platform_limits_solaris.cpp
>> index 9717d98ebf1..6ec1a1bdd11 100644
>> ---
>> a/libsanitizer/sanitizer_common/sanitizer_platform_limits_solaris.cpp
>> +++
>> b/libsanitizer/sanitizer_common/sanitizer_platform_limits_solaris.cpp
>> @@ -72,6 +72,7 @@ namespace __sanitizer {
>> unsigned struct_group_sz = sizeof(struct group);
>> unsigned siginfo_t_sz = sizeof(siginfo_t);
>> unsigned struct_sigaction_sz = sizeof(struct sigaction);
>> + unsigned struct_stack_t_sz = sizeof(stack_t);
>> unsigned struct_itimerval_sz = sizeof(struct itimerval);
>> unsigned pthread_t_sz = sizeof(pthread_t);
>> unsigned pthread_mutex_t_sz = sizeof(pthread_mutex_t);
>> diff --git
>> a/libsanitizer/sanitizer_common/sanitizer_platform_limits_solaris.h
>> b/libsanitizer/sanitizer_common/sanitizer_platform_limits_solaris.h
>> index 77ae6e6a44d..85995e79792 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_solaris.h
>> +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_solaris.h
>> @@ -38,6 +38,7 @@ extern unsigned struct_timezone_sz;
>> extern unsigned struct_tms_sz;
>> extern unsigned struct_itimerspec_sz;
>> extern unsigned struct_sigevent_sz;
>> +extern unsigned struct_stack_t_sz;
>> extern unsigned struct_sched_param_sz;
>> extern unsigned struct_statfs64_sz;
>> extern unsigned struct_statfs_sz;
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_posix.cpp
>> b/libsanitizer/sanitizer_common/sanitizer_posix.cpp
>> index d890a3a3177..e21661b42f8 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_posix.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_posix.cpp
>> @@ -347,9 +347,17 @@ int GetNamedMappingFd(const char *name, uptr
>> size, int *flags) {
>> CHECK(internal_strlen(name) < sizeof(shmname) - 10);
>> internal_snprintf(shmname, sizeof(shmname), "/dev/shm/%zu [%s]",
>> internal_getpid(), name);
>> + int o_cloexec = 0;
>> +#if defined(O_CLOEXEC)
>> + o_cloexec = O_CLOEXEC;
>> +#endif
>> int fd = ReserveStandardFds(
>> - internal_open(shmname, O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC,
>> S_IRWXU));
>> + internal_open(shmname, O_RDWR | O_CREAT | O_TRUNC | o_cloexec,
>> S_IRWXU));
>> CHECK_GE(fd, 0);
>> + if (!o_cloexec) {
>> + int res = fcntl(fd, F_SETFD, FD_CLOEXEC);
>> + CHECK_EQ(0, res);
>> + }
>> int res = internal_ftruncate(fd, size);
>> CHECK_EQ(0, res);
>> res = internal_unlink(shmname);
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_posix.h
>> b/libsanitizer/sanitizer_common/sanitizer_posix.h
>> index 05fb0f63020..a1b49702da2 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_posix.h
>> +++ b/libsanitizer/sanitizer_common/sanitizer_posix.h
>> @@ -39,7 +39,7 @@ uptr internal_write(fd_t fd, const void *buf, uptr
>> count);
>>
>> // Memory
>> uptr internal_mmap(void *addr, uptr length, int prot, int flags,
>> - int fd, OFF_T offset);
>> + int fd, u64 offset);
>> uptr internal_munmap(void *addr, uptr length);
>> int internal_mprotect(void *addr, uptr length, int prot);
>>
>> @@ -63,7 +63,7 @@ uptr internal_ptrace(int request, int pid, void
>> *addr, void *data);
>> uptr internal_waitpid(int pid, int *status, int options);
>>
>> int internal_fork();
>> -fd_t internal_spawn(const char *argv[], pid_t *pid);
>> +fd_t internal_spawn(const char *argv[], const char *envp[], pid_t
>> *pid);
>>
>> int internal_sysctl(const int *name, unsigned int namelen, void *oldp,
>> uptr *oldlenp, const void *newp, uptr newlen);
>> diff --git
>> a/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp
>> b/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp
>> index 304b3a01a08..f920172c06d 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp
>> @@ -426,7 +426,8 @@ void AdjustStackSize(void *attr_) {
>> #endif // !SANITIZER_GO
>>
>> pid_t StartSubprocess(const char *program, const char *const argv[],
>> - fd_t stdin_fd, fd_t stdout_fd, fd_t stderr_fd) {
>> + const char *const envp[], fd_t stdin_fd, fd_t
>> stdout_fd,
>> + fd_t stderr_fd) {
>> auto file_closer = at_scope_exit([&] {
>> if (stdin_fd != kInvalidFd) {
>> internal_close(stdin_fd);
>> @@ -469,7 +470,8 @@ pid_t StartSubprocess(const char *program, const
>> char *const argv[],
>>
>> for (int fd = sysconf(_SC_OPEN_MAX); fd > 2; fd--)
>> internal_close(fd);
>>
>> - execv(program, const_cast<char **>(&argv[0]));
>> + internal_execve(program, const_cast<char **>(&argv[0]),
>> + const_cast<char *const *>(envp));
>> internal__exit(1);
>> }
>>
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_procmaps.h
>> b/libsanitizer/sanitizer_common/sanitizer_procmaps.h
>> index d0e5245f84d..665ed45fa93 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_procmaps.h
>> +++ b/libsanitizer/sanitizer_common/sanitizer_procmaps.h
>> @@ -15,18 +15,19 @@
>>
>> #include "sanitizer_platform.h"
>>
>> -#if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD
>> || \
>> - SANITIZER_OPENBSD || SANITIZER_MAC || SANITIZER_SOLARIS
>> +#if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || \
>> + SANITIZER_OPENBSD || SANITIZER_MAC || SANITIZER_SOLARIS || \
>> + SANITIZER_FUCHSIA
>>
>> #include "sanitizer_common.h"
>> #include "sanitizer_internal_defs.h"
>> +#include "sanitizer_fuchsia.h"
>> #include "sanitizer_linux.h"
>> #include "sanitizer_mac.h"
>> #include "sanitizer_mutex.h"
>>
>> namespace __sanitizer {
>>
>> -
>> // Memory protection masks.
>> static const uptr kProtectionRead = 1;
>> static const uptr kProtectionWrite = 2;
>> diff --git
>> a/libsanitizer/sanitizer_common/sanitizer_procmaps_fuchsia.cpp
>> b/libsanitizer/sanitizer_common/sanitizer_procmaps_fuchsia.cpp
>> new file mode 100644
>> index 00000000000..cc3e9be0645
>> --- /dev/null
>> +++ b/libsanitizer/sanitizer_common/sanitizer_procmaps_fuchsia.cpp
>> @@ -0,0 +1,80 @@
>> +//===-- sanitizer_procmaps_fuchsia.cpp
>> +//----------------------------------------===//
>> +//
>> +// Part of the LLVM Project, under the Apache License v2.0 with LLVM
>> Exceptions.
>> +// See https://llvm.org/LICENSE.txt for license information.
>> +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
>> +//
>> +//===----------------------------------------------------------------------===//
>>
>> +//
>> +// Information about the process mappings (Fuchsia-specific parts).
>> +//===----------------------------------------------------------------------===//
>>
>> +
>> +#include "sanitizer_platform.h"
>> +#if SANITIZER_FUCHSIA
>> +#include <zircon/process.h>
>> +#include <zircon/syscalls.h>
>> +
>> +#include "sanitizer_common.h"
>> +#include "sanitizer_procmaps.h"
>> +
>> +namespace __sanitizer {
>> +
>> +// The cache flag is ignored on Fuchsia because a process can always
>> get this
>> +// information via its process-self handle.
>> +MemoryMappingLayout::MemoryMappingLayout(bool) { Reset(); }
>> +
>> +void MemoryMappingLayout::Reset() {
>> + data_.data.clear();
>> + data_.current = 0;
>> +
>> + size_t count;
>> + zx_status_t status = _zx_object_get_info(
>> + _zx_process_self(), ZX_INFO_PROCESS_MAPS, nullptr, 0, nullptr,
>> &count);
>> + if (status != ZX_OK) {
>> + return;
>> + }
>> +
>> + size_t filled;
>> + do {
>> + data_.data.resize(count);
>> + status = _zx_object_get_info(
>> + _zx_process_self(), ZX_INFO_PROCESS_MAPS, data_.data.data(),
>> + count * sizeof(zx_info_maps_t), &filled, &count);
>> + if (status != ZX_OK) {
>> + data_.data.clear();
>> + return;
>> + }
>> + } while (filled < count);
>> +}
>> +
>> +MemoryMappingLayout::~MemoryMappingLayout() {}
>> +
>> +bool MemoryMappingLayout::Error() const { return data_.data.empty(); }
>> +
>> +bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) {
>> + while (data_.current < data_.data.size()) {
>> + const auto &entry = data_.data[data_.current++];
>> + if (entry.type == ZX_INFO_MAPS_TYPE_MAPPING) {
>> + segment->start = entry.base;
>> + segment->end = entry.base + entry.size;
>> + segment->offset = entry.u.mapping.vmo_offset;
>> + const auto flags = entry.u.mapping.mmu_flags;
>> + segment->protection =
>> + ((flags & ZX_VM_PERM_READ) ? kProtectionRead : 0) |
>> + ((flags & ZX_VM_PERM_WRITE) ? kProtectionWrite : 0) |
>> + ((flags & ZX_VM_PERM_EXECUTE) ? kProtectionExecute : 0);
>> + if (segment->filename && segment->filename_size > 0) {
>> + uptr len = Min(sizeof(entry.name), segment->filename_size) - 1;
>> + internal_strncpy(segment->filename, entry.name, len);
>> + segment->filename[len] = 0;
>> + }
>> + return true;
>> + }
>> + }
>> + return false;
>> +}
>> +
>> +} // namespace __sanitizer
>> +
>> +#endif // SANITIZER_FUCHSIA
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_ptrauth.h
>> b/libsanitizer/sanitizer_common/sanitizer_ptrauth.h
>> new file mode 100644
>> index 00000000000..4d0d96a64f6
>> --- /dev/null
>> +++ b/libsanitizer/sanitizer_common/sanitizer_ptrauth.h
>> @@ -0,0 +1,21 @@
>> +//===-- sanitizer_ptrauth.h -------------------------------------*-
>> C++ -*-===//
>> +//
>> +// Part of the LLVM Project, under the Apache License v2.0 with LLVM
>> Exceptions.
>> +// See https://llvm.org/LICENSE.txt for license information.
>> +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
>> +//
>> +//===----------------------------------------------------------------------===//
>>
>> +
>> +#ifndef SANITIZER_PTRAUTH_H
>> +#define SANITIZER_PTRAUTH_H
>> +
>> +#if __has_feature(ptrauth_calls)
>> +#include <ptrauth.h>
>> +#else
>> +// Copied from <ptrauth.h>
>> +#define ptrauth_strip(__value, __key) __value
>> +#define ptrauth_auth_data(__value, __old_key, __old_data) __value
>> +#define ptrauth_string_discriminator(__string) ((int)0)
>> +#endif
>> +
>> +#endif // SANITIZER_PTRAUTH_H
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_rtems.cpp
>> b/libsanitizer/sanitizer_common/sanitizer_rtems.cpp
>> index 0d2576c00ab..29bcfcfa6f1 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_rtems.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_rtems.cpp
>> @@ -49,6 +49,10 @@ uptr internal_getpid() {
>> return getpid();
>> }
>>
>> +int internal_dlinfo(void *handle, int request, void *p) {
>> + UNIMPLEMENTED();
>> +}
>> +
>> bool FileExists(const char *filename) {
>> struct stat st;
>> if (stat(filename, &st))
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp
>> b/libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp
>> index ce75cbe5d26..ef14fb704ee 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp
>> @@ -60,8 +60,8 @@ static inline uhwptr *GetCanonicFrame(uptr bp,
>> // Nope, this does not look right either. This means the frame
>> after next does
>> // not have a valid frame pointer, but we can still extract the
>> caller PC.
>> // Unfortunately, there is no way to decide between GCC and LLVM
>> frame
>> - // layouts. Assume GCC.
>> - return bp_prev - 1;
>> + // layouts. Assume LLVM.
>> + return bp_prev;
>> #else
>> return (uhwptr*)bp;
>> #endif
>> @@ -84,21 +84,14 @@ void BufferedStackTrace::UnwindFast(uptr pc, uptr
>> bp, uptr stack_top,
>> IsAligned((uptr)frame, sizeof(*frame)) &&
>> size < max_depth) {
>> #ifdef __powerpc__
>> - // PowerPC ABIs specify that the return address is saved on the
>> - // *caller's* stack frame. Thus we must dereference the back chain
>> - // to find the caller frame before extracting it.
>> + // PowerPC ABIs specify that the return address is saved at offset
>> + // 16 of the *caller's* stack frame. Thus we must dereference the
>> + // back chain to find the caller frame before extracting it.
>> uhwptr *caller_frame = (uhwptr*)frame[0];
>> if (!IsValidFrame((uptr)caller_frame, stack_top, bottom) ||
>> !IsAligned((uptr)caller_frame, sizeof(uhwptr)))
>> break;
>> - // For most ABIs the offset where the return address is saved is
>> two
>> - // register sizes. The exception is the SVR4 ABI, which uses an
>> - // offset of only one register size.
>> -#ifdef _CALL_SYSV
>> - uhwptr pc1 = caller_frame[1];
>> -#else
>> uhwptr pc1 = caller_frame[2];
>> -#endif
>> #elif defined(__s390__)
>> uhwptr pc1 = frame[14];
>> #else
>> diff --git
>> a/libsanitizer/sanitizer_common/sanitizer_stoptheworld_fuchsia.cpp
>> b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_fuchsia.cpp
>> new file mode 100644
>> index 00000000000..3a246443ed9
>> --- /dev/null
>> +++ b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_fuchsia.cpp
>> @@ -0,0 +1,42 @@
>> +//===-- sanitizer_stoptheworld_fuchsia.cpp
>> -------------------------------===//
>> +//
>> +// Part of the LLVM Project, under the Apache License v2.0 with LLVM
>> Exceptions.
>> +// See https://llvm.org/LICENSE.txt for license information.
>> +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
>> +//
>> +//===---------------------------------------------------------------------===//
>>
>> +//
>> +// See sanitizer_stoptheworld.h for details.
>> +//
>> +//===---------------------------------------------------------------------===//
>>
>> +
>> +#include "sanitizer_platform.h"
>> +
>> +#if SANITIZER_FUCHSIA
>> +
>> +#include <zircon/sanitizer.h>
>> +
>> +#include "sanitizer_stoptheworld.h"
>> +
>> +namespace __sanitizer {
>> +
>> +// The Fuchsia implementation stops the world but doesn't offer a real
>> +// SuspendedThreadsList argument. This is enough for ASan's use case,
>> +// and LSan does not use this API on Fuchsia.
>> +void StopTheWorld(StopTheWorldCallback callback, void *argument) {
>> + struct Params {
>> + StopTheWorldCallback callback;
>> + void *argument;
>> + } params = {callback, argument};
>> + __sanitizer_memory_snapshot(
>> + nullptr, nullptr, nullptr, nullptr,
>> + [](zx_status_t, void *data) {
>> + auto params = reinterpret_cast<Params *>(data);
>> + params->callback({}, params->argument);
>> + },
>> + ¶ms);
>> +}
>> +
>> +} // namespace __sanitizer
>> +
>> +#endif // SANITIZER_FUCHSIA
>> diff --git
>> a/libsanitizer/sanitizer_common/sanitizer_stoptheworld_mac.cpp
>> b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_mac.cpp
>> index 9dffd21ecb7..6c577426ad5 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_stoptheworld_mac.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_mac.cpp
>> @@ -50,7 +50,7 @@ struct RunThreadArgs {
>> void *argument;
>> };
>>
>> -void RunThread(void *arg) {
>> +void *RunThread(void *arg) {
>> struct RunThreadArgs *run_args = (struct RunThreadArgs *)arg;
>> SuspendedThreadsListMac suspended_threads_list;
>>
>> @@ -59,7 +59,7 @@ void RunThread(void *arg) {
>> kern_return_t err = task_threads(mach_task_self(), &threads,
>> &num_threads);
>> if (err != KERN_SUCCESS) {
>> VReport(1, "Failed to get threads for task (errno %d).\n", err);
>> - return;
>> + return nullptr;
>> }
>>
>> thread_t thread_self = mach_thread_self();
>> @@ -76,6 +76,7 @@ void RunThread(void *arg) {
>> for (unsigned int i = 0; i < num_suspended; ++i) {
>> thread_resume(suspended_threads_list.GetThread(i));
>> }
>> + return nullptr;
>> }
>>
>> void StopTheWorld(StopTheWorldCallback callback, void *argument) {
>> @@ -159,7 +160,11 @@ PtraceRegistersStatus
>> SuspendedThreadsListMac::GetRegistersAndSP(
>> }
>>
>> internal_memcpy(buffer, ®s, sizeof(regs));
>> +#if defined(__aarch64__) && defined(arm_thread_state64_get_sp)
>> + *sp = arm_thread_state64_get_sp(regs);
>> +#else
>> *sp = regs.SP_REG;
>> +#endif
>>
>> // On x86_64 and aarch64, we must account for the stack redzone,
>> which is 128
>> // bytes.
>> diff --git
>> a/libsanitizer/sanitizer_common/sanitizer_stoptheworld_netbsd_libcdep.cpp
>> b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_netbsd_libcdep.cpp
>>
>> index 5690d75097f..1ed21343254 100644
>> ---
>> a/libsanitizer/sanitizer_common/sanitizer_stoptheworld_netbsd_libcdep.cpp
>> +++
>> b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_netbsd_libcdep.cpp
>> @@ -120,10 +120,18 @@ bool ThreadSuspender::SuspendAllThreads() {
>>
>> VReport(2, "Attached to process %d.\n", pid_);
>>
>> +#ifdef PT_LWPNEXT
>> + struct ptrace_lwpstatus pl;
>> + int op = PT_LWPNEXT;
>> +#else
>> struct ptrace_lwpinfo pl;
>> - int val;
>> + int op = PT_LWPINFO;
>> +#endif
>> +
>> pl.pl_lwpid = 0;
>> - while ((val = ptrace(PT_LWPINFO, pid_, (void *)&pl, sizeof(pl)))
>> != -1 &&
>> +
>> + int val;
>> + while ((val = ptrace(op, pid_, (void *)&pl, sizeof(pl))) != -1 &&
>> pl.pl_lwpid != 0) {
>> suspended_threads_list_.Append(pl.pl_lwpid);
>> VReport(2, "Appended thread %d in process %d.\n", pl.pl_lwpid,
>> pid_);
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer.cpp
>> b/libsanitizer/sanitizer_common/sanitizer_symbolizer.cpp
>> index ce2ece5f4d5..0c4b84c767a 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer.cpp
>> @@ -126,4 +126,10 @@ Symbolizer::SymbolizerScope::~SymbolizerScope() {
>> sym_->end_hook_();
>> }
>>
>> +void Symbolizer::LateInitializeTools() {
>> + for (auto &tool : tools_) {
>> + tool.LateInitialize();
>> + }
>> +}
>> +
>> } // namespace __sanitizer
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer.h
>> b/libsanitizer/sanitizer_common/sanitizer_symbolizer.h
>> index 51648e2d0e8..2476b0ea7bf 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer.h
>> +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer.h
>> @@ -209,6 +209,9 @@ class Symbolizer final {
>> private:
>> const Symbolizer *sym_;
>> };
>> +
>> + // Calls `LateInitialize()` on all items in `tools_`.
>> + void LateInitializeTools();
>> };
>>
>> #ifdef SANITIZER_WINDOWS
>> diff --git
>> a/libsanitizer/sanitizer_common/sanitizer_symbolizer_internal.h
>> b/libsanitizer/sanitizer_common/sanitizer_symbolizer_internal.h
>> index c04797dd61b..e4c351e667b 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_internal.h
>> +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_internal.h
>> @@ -69,6 +69,11 @@ class SymbolizerTool {
>> virtual const char *Demangle(const char *name) {
>> return nullptr;
>> }
>> +
>> + // Called during the LateInitialize phase of Sanitizer
>> initialization.
>> + // Usually this is a safe place to call code that might need to
>> use user
>> + // memory allocators.
>> + virtual void LateInitialize() {}
>> };
>>
>> // SymbolizerProcess encapsulates communication between the tool and
>> @@ -86,6 +91,8 @@ class SymbolizerProcess {
>> // Customizable by subclasses.
>> virtual bool StartSymbolizerSubprocess();
>> virtual bool ReadFromSymbolizer(char *buffer, uptr max_length);
>> + // Return the environment to run the symbolizer in.
>> + virtual char **GetEnvP() { return GetEnviron(); }
>>
>> private:
>> virtual bool ReachedEndOfOutput(const char *buffer, uptr length)
>> const {
>> diff --git
>> a/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cpp
>> b/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cpp
>> index 3b19a6836ec..490c6fe89be 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cpp
>> @@ -39,9 +39,9 @@ const char *ExtractToken(const char *str, const
>> char *delims, char **result) {
>> }
>>
>> const char *ExtractInt(const char *str, const char *delims, int
>> *result) {
>> - char *buff;
>> + char *buff = nullptr;
>> const char *ret = ExtractToken(str, delims, &buff);
>> - if (buff != 0) {
>> + if (buff) {
>> *result = (int)internal_atoll(buff);
>> }
>> InternalFree(buff);
>> @@ -49,9 +49,9 @@ const char *ExtractInt(const char *str, const char
>> *delims, int *result) {
>> }
>>
>> const char *ExtractUptr(const char *str, const char *delims, uptr
>> *result) {
>> - char *buff;
>> + char *buff = nullptr;
>> const char *ret = ExtractToken(str, delims, &buff);
>> - if (buff != 0) {
>> + if (buff) {
>> *result = (uptr)internal_atoll(buff);
>> }
>> InternalFree(buff);
>> @@ -59,9 +59,9 @@ const char *ExtractUptr(const char *str, const char
>> *delims, uptr *result) {
>> }
>>
>> const char *ExtractSptr(const char *str, const char *delims, sptr
>> *result) {
>> - char *buff;
>> + char *buff = nullptr;
>> const char *ret = ExtractToken(str, delims, &buff);
>> - if (buff != 0) {
>> + if (buff) {
>> *result = (sptr)internal_atoll(buff);
>> }
>> InternalFree(buff);
>> @@ -83,7 +83,7 @@ const char *ExtractTokenUpToDelimiter(const char
>> *str, const char *delimiter,
>>
>> SymbolizedStack *Symbolizer::SymbolizePC(uptr addr) {
>> BlockingMutexLock l(&mu_);
>> - const char *module_name;
>> + const char *module_name = nullptr;
>> uptr module_offset;
>> ModuleArch arch;
>> SymbolizedStack *res = SymbolizedStack::New(addr);
>> @@ -103,7 +103,7 @@ SymbolizedStack *Symbolizer::SymbolizePC(uptr
>> addr) {
>>
>> bool Symbolizer::SymbolizeData(uptr addr, DataInfo *info) {
>> BlockingMutexLock l(&mu_);
>> - const char *module_name;
>> + const char *module_name = nullptr;
>> uptr module_offset;
>> ModuleArch arch;
>> if (!FindModuleNameAndOffsetForAddress(addr, &module_name,
>> &module_offset,
>> @@ -124,7 +124,7 @@ bool Symbolizer::SymbolizeData(uptr addr,
>> DataInfo *info) {
>>
>> bool Symbolizer::SymbolizeFrame(uptr addr, FrameInfo *info) {
>> BlockingMutexLock l(&mu_);
>> - const char *module_name;
>> + const char *module_name = nullptr;
>> if (!FindModuleNameAndOffsetForAddress(
>> addr, &module_name, &info->module_offset,
>> &info->module_arch))
>> return false;
>> @@ -175,7 +175,7 @@ bool
>> Symbolizer::FindModuleNameAndOffsetForAddress(uptr address,
>> uptr
>> *module_offset,
>> ModuleArch
>> *module_arch) {
>> const LoadedModule *module = FindModuleForAddress(address);
>> - if (module == nullptr)
>> + if (!module)
>> return false;
>> *module_name = module->full_name();
>> *module_offset = address - module->base_address();
>> @@ -292,7 +292,7 @@ LLVMSymbolizer::LLVMSymbolizer(const char *path,
>> LowLevelAllocator *allocator)
>> // Windows, so extract tokens from the right hand side first. The
>> column info is
>> // also optional.
>> static const char *ParseFileLineInfo(AddressInfo *info, const char
>> *str) {
>> - char *file_line_info = 0;
>> + char *file_line_info = nullptr;
>> str = ExtractToken(str, "\n", &file_line_info);
>> CHECK(file_line_info);
>>
>> @@ -323,7 +323,7 @@ void ParseSymbolizePCOutput(const char *str,
>> SymbolizedStack *res) {
>> bool top_frame = true;
>> SymbolizedStack *last = res;
>> while (true) {
>> - char *function_name = 0;
>> + char *function_name = nullptr;
>> str = ExtractToken(str, "\n", &function_name);
>> CHECK(function_name);
>> if (function_name[0] == '\0') {
>> @@ -402,32 +402,29 @@ bool LLVMSymbolizer::SymbolizePC(uptr addr,
>> SymbolizedStack *stack) {
>> AddressInfo *info = &stack->info;
>> const char *buf = FormatAndSendCommand(
>> "CODE", info->module, info->module_offset, info->module_arch);
>> - if (buf) {
>> - ParseSymbolizePCOutput(buf, stack);
>> - return true;
>> - }
>> - return false;
>> + if (!buf)
>> + return false;
>> + ParseSymbolizePCOutput(buf, stack);
>> + return true;
>> }
>>
>> bool LLVMSymbolizer::SymbolizeData(uptr addr, DataInfo *info) {
>> const char *buf = FormatAndSendCommand(
>> "DATA", info->module, info->module_offset, info->module_arch);
>> - if (buf) {
>> - ParseSymbolizeDataOutput(buf, info);
>> - info->start += (addr - info->module_offset); // Add the base
>> address.
>> - return true;
>> - }
>> - return false;
>> + if (!buf)
>> + return false;
>> + ParseSymbolizeDataOutput(buf, info);
>> + info->start += (addr - info->module_offset); // Add the base address.
>> + return true;
>> }
>>
>> bool LLVMSymbolizer::SymbolizeFrame(uptr addr, FrameInfo *info) {
>> const char *buf = FormatAndSendCommand(
>> "FRAME", info->module, info->module_offset, info->module_arch);
>> - if (buf) {
>> - ParseSymbolizeFrameOutput(buf, &info->locals);
>> - return true;
>> - }
>> - return false;
>> + if (!buf)
>> + return false;
>> + ParseSymbolizeFrameOutput(buf, &info->locals);
>> + return true;
>> }
>>
>> const char *LLVMSymbolizer::FormatAndSendCommand(const char
>> *command_prefix,
>> @@ -435,21 +432,21 @@ const char
>> *LLVMSymbolizer::FormatAndSendCommand(const char *command_prefix,
>> uptr module_offset,
>> ModuleArch arch) {
>> CHECK(module_name);
>> - if (arch == kModuleArchUnknown) {
>> - if (internal_snprintf(buffer_, kBufferSize, "%s \"%s\" 0x%zx\n",
>> - command_prefix, module_name,
>> - module_offset) >=
>> static_cast<int>(kBufferSize)) {
>> - Report("WARNING: Command buffer too small");
>> - return nullptr;
>> - }
>> - } else {
>> - if (internal_snprintf(buffer_, kBufferSize, "%s \"%s:%s\" 0x%zx\n",
>> - command_prefix, module_name,
>> ModuleArchToString(arch),
>> - module_offset) >=
>> static_cast<int>(kBufferSize)) {
>> - Report("WARNING: Command buffer too small");
>> - return nullptr;
>> - }
>> + int size_needed = 0;
>> + if (arch == kModuleArchUnknown)
>> + size_needed = internal_snprintf(buffer_, kBufferSize, "%s \"%s\"
>> 0x%zx\n",
>> + command_prefix, module_name,
>> module_offset);
>> + else
>> + size_needed = internal_snprintf(buffer_, kBufferSize,
>> + "%s \"%s:%s\" 0x%zx\n",
>> command_prefix,
>> + module_name,
>> ModuleArchToString(arch),
>> + module_offset);
>> +
>> + if (size_needed >= static_cast<int>(kBufferSize)) {
>> + Report("WARNING: Command buffer too small");
>> + return nullptr;
>> }
>> +
>> return symbolizer_process_->SendCommand(buffer_);
>> }
>>
>> @@ -492,16 +489,16 @@ const char
>> *SymbolizerProcess::SendCommand(const char *command) {
>> Report("WARNING: Failed to use and restart external
>> symbolizer!\n");
>> failed_to_start_ = true;
>> }
>> - return 0;
>> + return nullptr;
>> }
>>
>> const char *SymbolizerProcess::SendCommandImpl(const char *command) {
>> if (input_fd_ == kInvalidFd || output_fd_ == kInvalidFd)
>> - return 0;
>> + return nullptr;
>> if (!WriteToSymbolizer(command, internal_strlen(command)))
>> - return 0;
>> + return nullptr;
>> if (!ReadFromSymbolizer(buffer_, kBufferSize))
>> - return 0;
>> + return nullptr;
>> return buffer_;
>> }
>>
>> diff --git
>> a/libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.cpp
>> b/libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.cpp
>> index a619ed092f0..cc233408d0c 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.cpp
>> @@ -20,6 +20,7 @@
>>
>> #include <dlfcn.h>
>> #include <errno.h>
>> +#include <mach/mach.h>
>> #include <stdlib.h>
>> #include <sys/wait.h>
>> #include <unistd.h>
>> @@ -31,6 +32,9 @@ bool DlAddrSymbolizer::SymbolizePC(uptr addr,
>> SymbolizedStack *stack) {
>> Dl_info info;
>> int result = dladdr((const void *)addr, &info);
>> if (!result) return false;
>> +
>> + CHECK(addr >= reinterpret_cast<uptr>(info.dli_saddr));
>> + stack->info.function_offset = addr -
>> reinterpret_cast<uptr>(info.dli_saddr);
>> const char *demangled = DemangleSwiftAndCXX(info.dli_sname);
>> if (!demangled) return false;
>> stack->info.function = internal_strdup(demangled);
>> @@ -47,18 +51,65 @@ bool DlAddrSymbolizer::SymbolizeData(uptr addr,
>> DataInfo *datainfo) {
>> return true;
>> }
>>
>> +#define K_ATOS_ENV_VAR "__check_mach_ports_lookup"
>> +
>> +// This cannot live in `AtosSymbolizerProcess` because instances of
>> that object
>> +// are allocated by the internal allocator which under ASan is
>> poisoned with
>> +// kAsanInternalHeapMagic.
>> +static char kAtosMachPortEnvEntry[] = K_ATOS_ENV_VAR
>> "=000000000000000";
>> +
>> class AtosSymbolizerProcess : public SymbolizerProcess {
>> public:
>> - explicit AtosSymbolizerProcess(const char *path, pid_t parent_pid)
>> + explicit AtosSymbolizerProcess(const char *path)
>> : SymbolizerProcess(path, /*use_posix_spawn*/ true) {
>> - // Put the string command line argument in the object so that it
>> outlives
>> - // the call to GetArgV.
>> - internal_snprintf(pid_str_, sizeof(pid_str_), "%d", parent_pid);
>> + pid_str_[0] = '\0';
>> + }
>> +
>> + void LateInitialize() {
>> + if (SANITIZER_IOSSIM) {
>> + // `putenv()` may call malloc/realloc so it is only safe to do
>> this
>> + // during LateInitialize() or later (i.e. we can't do this in the
>> + // constructor). We also can't do this in
>> `StartSymbolizerSubprocess()`
>> + // because in TSan we switch allocators when we're symbolizing.
>> + // We use `putenv()` rather than `setenv()` so that we can
>> later directly
>> + // write into the storage without LibC getting involved to
>> change what the
>> + // variable is set to
>> + int result = putenv(kAtosMachPortEnvEntry);
>> + CHECK_EQ(result, 0);
>> + }
>> }
>>
>> private:
>> bool StartSymbolizerSubprocess() override {
>> // Configure sandbox before starting atos process.
>> +
>> + // Put the string command line argument in the object so that it
>> outlives
>> + // the call to GetArgV.
>> + internal_snprintf(pid_str_, sizeof(pid_str_), "%d",
>> internal_getpid());
>> +
>> + if (SANITIZER_IOSSIM) {
>> + // `atos` in the simulator is restricted in its ability to
>> retrieve the
>> + // task port for the target process (us) so we need to do
>> extra work
>> + // to pass our task port to it.
>> + mach_port_t ports[]{mach_task_self()};
>> + kern_return_t ret =
>> + mach_ports_register(mach_task_self(), ports, /*count=*/1);
>> + CHECK_EQ(ret, KERN_SUCCESS);
>> +
>> + // Set environment variable that signals to `atos` that it
>> should look
>> + // for our task port. We can't call `setenv()` here because it
>> might call
>> + // malloc/realloc. To avoid that we instead update the
>> + // `mach_port_env_var_entry_` variable with our current PID.
>> + uptr count = internal_snprintf(kAtosMachPortEnvEntry,
>> + sizeof(kAtosMachPortEnvEntry),
>> + K_ATOS_ENV_VAR "=%s", pid_str_);
>> + CHECK_GE(count, sizeof(K_ATOS_ENV_VAR) +
>> internal_strlen(pid_str_));
>> + // Document our assumption but without calling `getenv()` in
>> normal
>> + // builds.
>> + DCHECK(getenv(K_ATOS_ENV_VAR));
>> + DCHECK_EQ(internal_strcmp(getenv(K_ATOS_ENV_VAR), pid_str_), 0);
>> + }
>> +
>> return SymbolizerProcess::StartSymbolizerSubprocess();
>> }
>>
>> @@ -82,8 +133,14 @@ class AtosSymbolizerProcess : public
>> SymbolizerProcess {
>> }
>>
>> char pid_str_[16];
>> + // Space for `\0` in `K_ATOS_ENV_VAR` is reused for `=`.
>> + static_assert(sizeof(kAtosMachPortEnvEntry) ==
>> + (sizeof(K_ATOS_ENV_VAR) + sizeof(pid_str_)),
>> + "sizes should match");
>> };
>>
>> +#undef K_ATOS_ENV_VAR
>> +
>> static bool ParseCommandOutput(const char *str, uptr addr, char
>> **out_name,
>> char **out_module, char **out_file,
>> uptr *line,
>> uptr *start_address) {
>> @@ -135,7 +192,7 @@ static bool ParseCommandOutput(const char *str,
>> uptr addr, char **out_name,
>> }
>>
>> AtosSymbolizer::AtosSymbolizer(const char *path, LowLevelAllocator
>> *allocator)
>> - : process_(new(*allocator) AtosSymbolizerProcess(path,
>> getpid())) {}
>> + : process_(new (*allocator) AtosSymbolizerProcess(path)) {}
>>
>> bool AtosSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) {
>> if (!process_) return false;
>> @@ -145,12 +202,29 @@ bool AtosSymbolizer::SymbolizePC(uptr addr,
>> SymbolizedStack *stack) {
>> const char *buf = process_->SendCommand(command);
>> if (!buf) return false;
>> uptr line;
>> + uptr start_address = AddressInfo::kUnknown;
>> if (!ParseCommandOutput(buf, addr, &stack->info.function,
>> &stack->info.module,
>> - &stack->info.file, &line, nullptr)) {
>> + &stack->info.file, &line, &start_address)) {
>> process_ = nullptr;
>> return false;
>> }
>> stack->info.line = (int)line;
>> +
>> + if (start_address == AddressInfo::kUnknown) {
>> + // Fallback to dladdr() to get function start address if atos
>> doesn't report
>> + // it.
>> + Dl_info info;
>> + int result = dladdr((const void *)addr, &info);
>> + if (result)
>> + start_address = reinterpret_cast<uptr>(info.dli_saddr);
>> + }
>> +
>> + // Only assig to `function_offset` if we were able to get the
>> function's
>> + // start address.
>> + if (start_address != AddressInfo::kUnknown) {
>> + CHECK(addr >= start_address);
>> + stack->info.function_offset = addr - start_address;
>> + }
>> return true;
>> }
>>
>> @@ -168,6 +242,8 @@ bool AtosSymbolizer::SymbolizeData(uptr addr,
>> DataInfo *info) {
>> return true;
>> }
>>
>> +void AtosSymbolizer::LateInitialize() { process_->LateInitialize(); }
>> +
>> } // namespace __sanitizer
>>
>> #endif // SANITIZER_MAC
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.h
>> b/libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.h
>> index 68521375e64..8996131fc13 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.h
>> +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.h
>> @@ -35,6 +35,7 @@ class AtosSymbolizer : public SymbolizerTool {
>>
>> bool SymbolizePC(uptr addr, SymbolizedStack *stack) override;
>> bool SymbolizeData(uptr addr, DataInfo *info) override;
>> + void LateInitialize() override;
>>
>> private:
>> AtosSymbolizerProcess *process_;
>> diff --git
>> a/libsanitizer/sanitizer_common/sanitizer_symbolizer_markup.cpp
>> b/libsanitizer/sanitizer_common/sanitizer_symbolizer_markup.cpp
>> index 57b4d0c9d96..2963af95360 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_markup.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_markup.cpp
>> @@ -94,7 +94,9 @@ Symbolizer *Symbolizer::PlatformInit() {
>> return new (symbolizer_allocator_) Symbolizer({});
>> }
>>
>> -void Symbolizer::LateInitialize() { Symbolizer::GetOrInit(); }
>> +void Symbolizer::LateInitialize() {
>> + Symbolizer::GetOrInit()->LateInitializeTools();
>> +}
>>
>> void StartReportDeadlySignal() {}
>> void ReportDeadlySignal(const SignalContext &sig, u32 tid,
>> diff --git
>> a/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp
>> b/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp
>> index c123ecb1120..d7b931bc237 100644
>> ---
>> a/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp
>> +++
>> b/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp
>> @@ -151,9 +151,19 @@ bool
>> SymbolizerProcess::StartSymbolizerSubprocess() {
>> GetArgV(path_, argv);
>> pid_t pid;
>>
>> + // Report how symbolizer is being launched for debugging purposes.
>> + if (Verbosity() >= 3) {
>> + // Only use `Report` for first line so subsequent prints don't
>> get prefixed
>> + // with current PID.
>> + Report("Launching Symbolizer process: ");
>> + for (unsigned index = 0; index < kArgVMax && argv[index]; ++index)
>> + Printf("%s ", argv[index]);
>> + Printf("\n");
>> + }
>> +
>> if (use_posix_spawn_) {
>> #if SANITIZER_MAC
>> - fd_t fd = internal_spawn(argv, &pid);
>> + fd_t fd = internal_spawn(argv, const_cast<const char
>> **>(GetEnvP()), &pid);
>> if (fd == kInvalidFd) {
>> Report("WARNING: failed to spawn external symbolizer (errno:
>> %d)\n",
>> errno);
>> @@ -173,7 +183,7 @@ bool
>> SymbolizerProcess::StartSymbolizerSubprocess() {
>> return false;
>> }
>>
>> - pid = StartSubprocess(path_, argv, /* stdin */ outfd[0],
>> + pid = StartSubprocess(path_, argv, GetEnvP(), /* stdin */ outfd[0],
>> /* stdout */ infd[1]);
>> if (pid < 0) {
>> internal_close(infd[0]);
>> @@ -478,7 +488,7 @@ Symbolizer *Symbolizer::PlatformInit() {
>> }
>>
>> void Symbolizer::LateInitialize() {
>> - Symbolizer::GetOrInit();
>> + Symbolizer::GetOrInit()->LateInitializeTools();
>> InitializeSwiftDemangler();
>> }
>>
>> diff --git
>> a/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cpp
>> b/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cpp
>> index 2808779156e..373437e7ee2 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cpp
>> @@ -310,7 +310,7 @@ Symbolizer *Symbolizer::PlatformInit() {
>> }
>>
>> void Symbolizer::LateInitialize() {
>> - Symbolizer::GetOrInit();
>> + Symbolizer::GetOrInit()->LateInitializeTools();
>> }
>>
>> } // namespace __sanitizer
>> diff --git
>> a/libsanitizer/sanitizer_common/sanitizer_syscalls_netbsd.inc
>> b/libsanitizer/sanitizer_common/sanitizer_syscalls_netbsd.inc
>> index 69e59871874..02b7e11b167 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_syscalls_netbsd.inc
>> +++ b/libsanitizer/sanitizer_common/sanitizer_syscalls_netbsd.inc
>> @@ -42,7 +42,7 @@
>> // DO NOT EDIT! THIS FILE HAS BEEN GENERATED!
>> //
>> // Generated with: generate_netbsd_syscalls.awk
>> -// Generated date: 2019-11-01
>> +// Generated date: 2019-12-24
>> // Generated from: syscalls.master,v 1.296 2019/09/22 22:59:39
>> christos Exp
>> //
>> //===----------------------------------------------------------------------===//
>>
>> @@ -323,6 +323,16 @@ PRE_SYSCALL(ptrace)
>> PRE_READ(addr_, struct_ptrace_ptrace_siginfo_struct_sz);
>> } else if (req_ == ptrace_pt_get_siginfo) {
>> PRE_WRITE(addr_, struct_ptrace_ptrace_siginfo_struct_sz);
>> + } else if (req_ == ptrace_pt_lwpstatus) {
>> + struct __sanitizer_ptrace_lwpstatus *addr =
>> + (struct __sanitizer_ptrace_lwpstatus *)addr_;
>> + PRE_READ(&addr->pl_lwpid, sizeof(__sanitizer_lwpid_t));
>> + PRE_WRITE(addr, struct_ptrace_ptrace_lwpstatus_struct_sz);
>> + } else if (req_ == ptrace_pt_lwpnext) {
>> + struct __sanitizer_ptrace_lwpstatus *addr =
>> + (struct __sanitizer_ptrace_lwpstatus *)addr_;
>> + PRE_READ(&addr->pl_lwpid, sizeof(__sanitizer_lwpid_t));
>> + PRE_WRITE(addr, struct_ptrace_ptrace_lwpstatus_struct_sz);
>> } else if (req_ == ptrace_pt_setregs) {
>> PRE_READ(addr_, struct_ptrace_reg_struct_sz);
>> } else if (req_ == ptrace_pt_getregs) {
>> @@ -366,6 +376,16 @@ POST_SYSCALL(ptrace)
>> POST_READ(addr_, struct_ptrace_ptrace_siginfo_struct_sz);
>> } else if (req_ == ptrace_pt_get_siginfo) {
>> POST_WRITE(addr_, struct_ptrace_ptrace_siginfo_struct_sz);
>> + } else if (req_ == ptrace_pt_lwpstatus) {
>> + struct __sanitizer_ptrace_lwpstatus *addr =
>> + (struct __sanitizer_ptrace_lwpstatus *)addr_;
>> + POST_READ(&addr->pl_lwpid, sizeof(__sanitizer_lwpid_t));
>> + POST_WRITE(addr, struct_ptrace_ptrace_lwpstatus_struct_sz);
>> + } else if (req_ == ptrace_pt_lwpnext) {
>> + struct __sanitizer_ptrace_lwpstatus *addr =
>> + (struct __sanitizer_ptrace_lwpstatus *)addr_;
>> + POST_READ(&addr->pl_lwpid, sizeof(__sanitizer_lwpid_t));
>> + POST_WRITE(addr, struct_ptrace_ptrace_lwpstatus_struct_sz);
>> } else if (req_ == ptrace_pt_setregs) {
>> POST_READ(addr_, struct_ptrace_reg_struct_sz);
>> } else if (req_ == ptrace_pt_getregs) {
>> diff --git a/libsanitizer/sanitizer_common/sanitizer_win.cpp
>> b/libsanitizer/sanitizer_common/sanitizer_win.cpp
>> index 36dde49d870..fca15beb616 100644
>> --- a/libsanitizer/sanitizer_common/sanitizer_win.cpp
>> +++ b/libsanitizer/sanitizer_common/sanitizer_win.cpp
>> @@ -94,6 +94,10 @@ uptr internal_getpid() {
>> return GetProcessId(GetCurrentProcess());
>> }
>>
>> +int internal_dlinfo(void *handle, int request, void *p) {
>> + UNIMPLEMENTED();
>> +}
>> +
>> // In contrast to POSIX, on Windows GetCurrentThreadId()
>> // returns a system-unique identifier.
>> tid_t GetTid() {
>> @@ -787,7 +791,7 @@ uptr GetRSS() {
>> return counters.WorkingSetSize;
>> }
>>
>> -void *internal_start_thread(void (*func)(void *arg), void *arg) {
>> return 0; }
>> +void *internal_start_thread(void *(*func)(void *arg), void *arg) {
>> return 0; }
>> void internal_join_thread(void *th) { }
>>
>> // ---------------------- BlockingMutex ---------------- {{{1
>> @@ -1060,7 +1064,8 @@ char **GetEnviron() {
>> }
>>
>> pid_t StartSubprocess(const char *program, const char *const argv[],
>> - fd_t stdin_fd, fd_t stdout_fd, fd_t stderr_fd) {
>> + const char *const envp[], fd_t stdin_fd, fd_t
>> stdout_fd,
>> + fd_t stderr_fd) {
>> // FIXME: implement on this platform
>> // Should be implemented based on
>> // SymbolizerProcess::StarAtSymbolizerSubprocess
>> diff --git a/libsanitizer/tsan/tsan_clock.cpp
>> b/libsanitizer/tsan/tsan_clock.cpp
>> index 4b7aa0653da..c91b29cb22b 100644
>> --- a/libsanitizer/tsan/tsan_clock.cpp
>> +++ b/libsanitizer/tsan/tsan_clock.cpp
>> @@ -30,6 +30,14 @@
>> // dst->clock[i] = max(dst->clock[i], clock[i]);
>> // }
>> //
>> +// void ThreadClock::releaseStoreAcquire(SyncClock *sc) const {
>> +// for (int i = 0; i < kMaxThreads; i++) {
>> +// tmp = clock[i];
>> +// clock[i] = max(clock[i], sc->clock[i]);
>> +// sc->clock[i] = tmp;
>> +// }
>> +// }
>> +//
>> // void ThreadClock::ReleaseStore(SyncClock *dst) const {
>> // for (int i = 0; i < kMaxThreads; i++)
>> // dst->clock[i] = clock[i];
>> @@ -107,13 +115,14 @@ static void UnrefClockBlock(ClockCache *c, u32
>> idx, uptr blocks) {
>> ThreadClock::ThreadClock(unsigned tid, unsigned reused)
>> : tid_(tid)
>> , reused_(reused + 1) // 0 has special meaning
>> + , last_acquire_()
>> + , global_acquire_()
>> , cached_idx_()
>> , cached_size_()
>> , cached_blocks_() {
>> CHECK_LT(tid, kMaxTidInClock);
>> CHECK_EQ(reused_, ((u64)reused_ << kClkBits) >> kClkBits);
>> nclk_ = tid_ + 1;
>> - last_acquire_ = 0;
>> internal_memset(clk_, 0, sizeof(clk_));
>> }
>>
>> @@ -177,6 +186,49 @@ void ThreadClock::acquire(ClockCache *c,
>> SyncClock *src) {
>> }
>> }
>>
>> +void ThreadClock::releaseStoreAcquire(ClockCache *c, SyncClock *sc) {
>> + DCHECK_LE(nclk_, kMaxTid);
>> + DCHECK_LE(sc->size_, kMaxTid);
>> +
>> + if (sc->size_ == 0) {
>> + // ReleaseStore will correctly set release_store_tid_,
>> + // which can be important for future operations.
>> + ReleaseStore(c, sc);
>> + return;
>> + }
>> +
>> + nclk_ = max(nclk_, (uptr) sc->size_);
>> +
>> + // Check if we need to resize sc.
>> + if (sc->size_ < nclk_)
>> + sc->Resize(c, nclk_);
>> +
>> + bool acquired = false;
>> +
>> + sc->Unshare(c);
>> + // Update sc->clk_.
>> + sc->FlushDirty();
>> + uptr i = 0;
>> + for (ClockElem &ce : *sc) {
>> + u64 tmp = clk_[i];
>> + if (clk_[i] < ce.epoch) {
>> + clk_[i] = ce.epoch;
>> + acquired = true;
>> + }
>> + ce.epoch = tmp;
>> + ce.reused = 0;
>> + i++;
>> + }
>> + sc->release_store_tid_ = kInvalidTid;
>> + sc->release_store_reused_ = 0;
>> +
>> + if (acquired) {
>> + CPP_STAT_INC(StatClockAcquiredSomething);
>> + last_acquire_ = clk_[tid_];
>> + ResetCached(c);
>> + }
>> +}
>> +
>> void ThreadClock::release(ClockCache *c, SyncClock *dst) {
>> DCHECK_LE(nclk_, kMaxTid);
>> DCHECK_LE(dst->size_, kMaxTid);
>> @@ -196,7 +248,7 @@ void ThreadClock::release(ClockCache *c,
>> SyncClock *dst) {
>> // Check if we had not acquired anything from other threads
>> // since the last release on dst. If so, we need to update
>> // only dst->elem(tid_).
>> - if (dst->elem(tid_).epoch > last_acquire_) {
>> + if (!HasAcquiredAfterRelease(dst)) {
>> UpdateCurrentThread(c, dst);
>> if (dst->release_store_tid_ != tid_ ||
>> dst->release_store_reused_ != reused_)
>> @@ -222,8 +274,6 @@ void ThreadClock::release(ClockCache *c,
>> SyncClock *dst) {
>> // Clear 'acquired' flag in the remaining elements.
>> if (nclk_ < dst->size_)
>> CPP_STAT_INC(StatClockReleaseClearTail);
>> - for (uptr i = nclk_; i < dst->size_; i++)
>> - dst->elem(i).reused = 0;
>> dst->release_store_tid_ = kInvalidTid;
>> dst->release_store_reused_ = 0;
>> // If we've acquired dst, remember this fact,
>> @@ -269,7 +319,7 @@ void ThreadClock::ReleaseStore(ClockCache *c,
>> SyncClock *dst) {
>>
>> if (dst->release_store_tid_ == tid_ &&
>> dst->release_store_reused_ == reused_ &&
>> - dst->elem(tid_).epoch > last_acquire_) {
>> + !HasAcquiredAfterRelease(dst)) {
>> CPP_STAT_INC(StatClockStoreFast);
>> UpdateCurrentThread(c, dst);
>> return;
>> @@ -351,6 +401,14 @@ bool ThreadClock::IsAlreadyAcquired(const
>> SyncClock *src) const {
>> return true;
>> }
>>
>> +// Checks whether the current thread has acquired anything
>> +// from other clocks after releasing to dst (directly or indirectly).
>> +bool ThreadClock::HasAcquiredAfterRelease(const SyncClock *dst) const {
>> + const u64 my_epoch = dst->elem(tid_).epoch;
>> + return my_epoch <= last_acquire_ ||
>> + my_epoch <= atomic_load_relaxed(&global_acquire_);
>> +}
>> +
>> // Sets a single element in the vector clock.
>> // This function is called only from weird places like AcquireGlobal.
>> void ThreadClock::set(ClockCache *c, unsigned tid, u64 v) {
>> diff --git a/libsanitizer/tsan/tsan_clock.h
>> b/libsanitizer/tsan/tsan_clock.h
>> index 6a1d15a2a16..736cdae06ba 100644
>> --- a/libsanitizer/tsan/tsan_clock.h
>> +++ b/libsanitizer/tsan/tsan_clock.h
>> @@ -134,10 +134,12 @@ class ThreadClock {
>> uptr size() const;
>>
>> void acquire(ClockCache *c, SyncClock *src);
>> + void releaseStoreAcquire(ClockCache *c, SyncClock *src);
>> void release(ClockCache *c, SyncClock *dst);
>> void acq_rel(ClockCache *c, SyncClock *dst);
>> void ReleaseStore(ClockCache *c, SyncClock *dst);
>> void ResetCached(ClockCache *c);
>> + void NoteGlobalAcquire(u64 v);
>>
>> void DebugReset();
>> void DebugDump(int(*printf)(const char *s, ...));
>> @@ -150,6 +152,53 @@ class ThreadClock {
>> // Current thread time when it acquired something from other
>> threads.
>> u64 last_acquire_;
>>
>> + // Last time another thread has done a global acquire of this
>> thread's clock.
>> + // It helps to avoid problem described in:
>> + // https://github.com/golang/go/issues/39186
>> + // See test/tsan/java_finalizer2.cpp for a regression test.
>> + // Note the failuire is _extremely_ hard to hit, so if you are trying
>> + // to reproduce it, you may want to run something like:
>> + // $ go get golang.org/x/tools/cmd/stress
>> + // $ stress -p=64 ./a.out
>> + //
>> + // The crux of the problem is roughly as follows.
>> + // A number of O(1) optimizations in the clocks algorithm assume
>> proper
>> + // transitive cumulative propagation of clock values. The
>> AcquireGlobal
>> + // operation may produce an inconsistent non-linearazable view of
>> + // thread clocks. Namely, it may acquire a later value from a thread
>> + // with a higher ID, but fail to acquire an earlier value from a
>> thread
>> + // with a lower ID. If a thread that executed AcquireGlobal then
>> releases
>> + // to a sync clock, it will spoil the sync clock with the
>> inconsistent
>> + // values. If another thread later releases to the sync clock, the
>> optimized
>> + // algorithm may break.
>> + //
>> + // The exact sequence of events that leads to the failure.
>> + // - thread 1 executes AcquireGlobal
>> + // - thread 1 acquires value 1 for thread 2
>> + // - thread 2 increments clock to 2
>> + // - thread 2 releases to sync object 1
>> + // - thread 3 at time 1
>> + // - thread 3 acquires from sync object 1
>> + // - thread 3 increments clock to 2
>> + // - thread 1 acquires value 2 for thread 3
>> + // - thread 1 releases to sync object 2
>> + // - sync object 2 clock has 1 for thread 2 and 2 for thread 3
>> + // - thread 3 releases to sync object 2
>> + // - thread 3 sees value 2 in the clock for itself
>> + // and decides that it has already released to the clock
>> + // and did not acquire anything from other threads after that
>> + // (the last_acquire_ check in release operation)
>> + // - thread 3 does not update the value for thread 2 in the clock
>> from 1 to 2
>> + // - thread 4 acquires from sync object 2
>> + // - thread 4 detects a false race with thread 2
>> + // as it should have been synchronized with thread 2 up to time 2,
>> + // but because of the broken clock it is now synchronized only
>> up to time 1
>> + //
>> + // The global_acquire_ value helps to prevent this scenario.
>> + // Namely, thread 3 will not trust any own clock values up to
>> global_acquire_
>> + // for the purposes of the last_acquire_ optimization.
>> + atomic_uint64_t global_acquire_;
>> +
>> // Cached SyncClock (without dirty entries and release_store_tid_).
>> // We reuse it for subsequent store-release operations without
>> intervening
>> // acquire operations. Since it is shared (and thus constant),
>> clock value
>> @@ -164,6 +213,7 @@ class ThreadClock {
>> u64 clk_[kMaxTidInClock]; // Fixed size vector clock.
>>
>> bool IsAlreadyAcquired(const SyncClock *src) const;
>> + bool HasAcquiredAfterRelease(const SyncClock *dst) const;
>> void UpdateCurrentThread(ClockCache *c, SyncClock *dst) const;
>> };
>>
>> @@ -185,6 +235,14 @@ ALWAYS_INLINE uptr ThreadClock::size() const {
>> return nclk_;
>> }
>>
>> +ALWAYS_INLINE void ThreadClock::NoteGlobalAcquire(u64 v) {
>> + // Here we rely on the fact that AcquireGlobal is protected by
>> + // ThreadRegistryLock, thus only one thread at a time executes it
>> + // and values passed to this function should not go backwards.
>> + CHECK_LE(atomic_load_relaxed(&global_acquire_), v);
>> + atomic_store_relaxed(&global_acquire_, v);
>> +}
>> +
>> ALWAYS_INLINE SyncClock::Iter SyncClock::begin() {
>> return Iter(this);
>> }
>> diff --git a/libsanitizer/tsan/tsan_interceptors_posix.cpp
>> b/libsanitizer/tsan/tsan_interceptors_posix.cpp
>> index 8aea1e4ec05..718957c3703 100644
>> --- a/libsanitizer/tsan/tsan_interceptors_posix.cpp
>> +++ b/libsanitizer/tsan/tsan_interceptors_posix.cpp
>> @@ -891,13 +891,16 @@ void DestroyThreadState() {
>> ThreadFinish(thr);
>> ProcUnwire(proc, thr);
>> ProcDestroy(proc);
>> + DTLS_Destroy();
>> + cur_thread_finalize();
>> +}
>> +
>> +void PlatformCleanUpThreadState(ThreadState *thr) {
>> ThreadSignalContext *sctx = thr->signal_ctx;
>> if (sctx) {
>> thr->signal_ctx = 0;
>> UnmapOrDie(sctx, sizeof(*sctx));
>> }
>> - DTLS_Destroy();
>> - cur_thread_finalize();
>> }
>> } // namespace __tsan
>>
>> @@ -1016,7 +1019,7 @@ TSAN_INTERCEPTOR(int, pthread_create,
>>
>> TSAN_INTERCEPTOR(int, pthread_join, void *th, void **ret) {
>> SCOPED_INTERCEPTOR_RAW(pthread_join, th, ret);
>> - int tid = ThreadTid(thr, pc, (uptr)th);
>> + int tid = ThreadConsumeTid(thr, pc, (uptr)th);
>> ThreadIgnoreBegin(thr, pc);
>> int res = BLOCK_REAL(pthread_join)(th, ret);
>> ThreadIgnoreEnd(thr, pc);
>> @@ -1029,8 +1032,8 @@ TSAN_INTERCEPTOR(int, pthread_join, void *th,
>> void **ret) {
>> DEFINE_REAL_PTHREAD_FUNCTIONS
>>
>> TSAN_INTERCEPTOR(int, pthread_detach, void *th) {
>> - SCOPED_TSAN_INTERCEPTOR(pthread_detach, th);
>> - int tid = ThreadTid(thr, pc, (uptr)th);
>> + SCOPED_INTERCEPTOR_RAW(pthread_detach, th);
>> + int tid = ThreadConsumeTid(thr, pc, (uptr)th);
>> int res = REAL(pthread_detach)(th);
>> if (res == 0) {
>> ThreadDetach(thr, pc, tid);
>> @@ -1050,8 +1053,8 @@ TSAN_INTERCEPTOR(void, pthread_exit, void
>> *retval) {
>>
>> #if SANITIZER_LINUX
>> TSAN_INTERCEPTOR(int, pthread_tryjoin_np, void *th, void **ret) {
>> - SCOPED_TSAN_INTERCEPTOR(pthread_tryjoin_np, th, ret);
>> - int tid = ThreadTid(thr, pc, (uptr)th);
>> + SCOPED_INTERCEPTOR_RAW(pthread_tryjoin_np, th, ret);
>> + int tid = ThreadConsumeTid(thr, pc, (uptr)th);
>> ThreadIgnoreBegin(thr, pc);
>> int res = REAL(pthread_tryjoin_np)(th, ret);
>> ThreadIgnoreEnd(thr, pc);
>> @@ -1064,8 +1067,8 @@ TSAN_INTERCEPTOR(int, pthread_tryjoin_np, void
>> *th, void **ret) {
>>
>> TSAN_INTERCEPTOR(int, pthread_timedjoin_np, void *th, void **ret,
>> const struct timespec *abstime) {
>> - SCOPED_TSAN_INTERCEPTOR(pthread_timedjoin_np, th, ret, abstime);
>> - int tid = ThreadTid(thr, pc, (uptr)th);
>> + SCOPED_INTERCEPTOR_RAW(pthread_timedjoin_np, th, ret, abstime);
>> + int tid = ThreadConsumeTid(thr, pc, (uptr)th);
>> ThreadIgnoreBegin(thr, pc);
>> int res = BLOCK_REAL(pthread_timedjoin_np)(th, ret, abstime);
>> ThreadIgnoreEnd(thr, pc);
>> diff --git a/libsanitizer/tsan/tsan_platform.h
>> b/libsanitizer/tsan/tsan_platform.h
>> index 63eb14fcd34..7256d64e507 100644
>> --- a/libsanitizer/tsan/tsan_platform.h
>> +++ b/libsanitizer/tsan/tsan_platform.h
>> @@ -1021,6 +1021,7 @@ int
>> call_pthread_cancel_with_cleanup(int(*fn)(void *c, void *m,
>> void(*cleanup)(void *arg), void *arg);
>>
>> void DestroyThreadState();
>> +void PlatformCleanUpThreadState(ThreadState *thr);
>>
>> } // namespace __tsan
>>
>> diff --git a/libsanitizer/tsan/tsan_platform_mac.cpp
>> b/libsanitizer/tsan/tsan_platform_mac.cpp
>> index 326ca8532e5..f92ecc5e40f 100644
>> --- a/libsanitizer/tsan/tsan_platform_mac.cpp
>> +++ b/libsanitizer/tsan/tsan_platform_mac.cpp
>> @@ -19,6 +19,7 @@
>> #include "sanitizer_common/sanitizer_libc.h"
>> #include "sanitizer_common/sanitizer_posix.h"
>> #include "sanitizer_common/sanitizer_procmaps.h"
>> +#include "sanitizer_common/sanitizer_ptrauth.h"
>> #include "sanitizer_common/sanitizer_stackdepot.h"
>> #include "tsan_platform.h"
>> #include "tsan_rtl.h"
>> @@ -75,9 +76,14 @@ static uptr main_thread_identity = 0;
>> ALIGNED(64) static char main_thread_state[sizeof(ThreadState)];
>> static ThreadState *main_thread_state_loc = (ThreadState
>> *)main_thread_state;
>>
>> +// We cannot use pthread_self() before libpthread has been
>> initialized. Our
>> +// current heuristic for guarding this is checking
>> `main_thread_identity` which
>> +// is only assigned in `__tsan::InitializePlatform`.
>> static ThreadState **cur_thread_location() {
>> + if (main_thread_identity == 0)
>> + return &main_thread_state_loc;
>> uptr thread_identity = (uptr)pthread_self();
>> - if (thread_identity == main_thread_identity ||
>> main_thread_identity == 0)
>> + if (thread_identity == main_thread_identity)
>> return &main_thread_state_loc;
>> return (ThreadState **)MemToShadow(thread_identity);
>> }
>> @@ -269,6 +275,8 @@ void InitializePlatform() {
>> uptr ExtractLongJmpSp(uptr *env) {
>> uptr mangled_sp = env[LONG_JMP_SP_ENV_SLOT];
>> uptr sp = mangled_sp ^ longjmp_xor_key;
>> + sp = (uptr)ptrauth_auth_data((void *)sp, ptrauth_key_asdb,
>> + ptrauth_string_discriminator("sp"));
>> return sp;
>> }
>>
>> diff --git a/libsanitizer/tsan/tsan_rtl.cpp
>> b/libsanitizer/tsan/tsan_rtl.cpp
>> index 3f3c0cce119..13c9b770f50 100644
>> --- a/libsanitizer/tsan/tsan_rtl.cpp
>> +++ b/libsanitizer/tsan/tsan_rtl.cpp
>> @@ -144,7 +144,7 @@ static void MemoryProfiler(Context *ctx, fd_t fd,
>> int i) {
>> WriteToFile(fd, buf.data(), internal_strlen(buf.data()));
>> }
>>
>> -static void BackgroundThread(void *arg) {
>> +static void *BackgroundThread(void *arg) {
>> // This is a non-initialized non-user thread, nothing to see here.
>> // We don't use ScopedIgnoreInterceptors, because we want ignores
>> to be
>> // enabled even when the thread function exits (e.g. during
>> pthread thread
>> @@ -220,6 +220,7 @@ static void BackgroundThread(void *arg) {
>> }
>> }
>> }
>> + return nullptr;
>> }
>>
>> static void StartBackgroundThread() {
>> @@ -494,14 +495,23 @@ int Finalize(ThreadState *thr) {
>> void ForkBefore(ThreadState *thr, uptr pc) {
>> ctx->thread_registry->Lock();
>> ctx->report_mtx.Lock();
>> + // Ignore memory accesses in the pthread_atfork callbacks.
>> + // If any of them triggers a data race we will deadlock
>> + // on the report_mtx.
>> + // We could ignore interceptors and sync operations as well,
>> + // but so far it's unclear if it will do more good or harm.
>> + // Unnecessarily ignoring things can lead to false positives later.
>> + ThreadIgnoreBegin(thr, pc);
>> }
>>
>> void ForkParentAfter(ThreadState *thr, uptr pc) {
>> + ThreadIgnoreEnd(thr, pc); // Begin is in ForkBefore.
>> ctx->report_mtx.Unlock();
>> ctx->thread_registry->Unlock();
>> }
>>
>> void ForkChildAfter(ThreadState *thr, uptr pc) {
>> + ThreadIgnoreEnd(thr, pc); // Begin is in ForkBefore.
>> ctx->report_mtx.Unlock();
>> ctx->thread_registry->Unlock();
>>
>> diff --git a/libsanitizer/tsan/tsan_rtl.h b/libsanitizer/tsan/tsan_rtl.h
>> index c38fc43a9f8..d3bb61ff87d 100644
>> --- a/libsanitizer/tsan/tsan_rtl.h
>> +++ b/libsanitizer/tsan/tsan_rtl.h
>> @@ -775,7 +775,7 @@ int ThreadCreate(ThreadState *thr, uptr pc, uptr
>> uid, bool detached);
>> void ThreadStart(ThreadState *thr, int tid, tid_t os_id,
>> ThreadType thread_type);
>> void ThreadFinish(ThreadState *thr);
>> -int ThreadTid(ThreadState *thr, uptr pc, uptr uid);
>> +int ThreadConsumeTid(ThreadState *thr, uptr pc, uptr uid);
>> void ThreadJoin(ThreadState *thr, uptr pc, int tid);
>> void ThreadDetach(ThreadState *thr, uptr pc, int tid);
>> void ThreadFinalize(ThreadState *thr);
>> @@ -813,10 +813,12 @@ void Acquire(ThreadState *thr, uptr pc, uptr
>> addr);
>> // approximation of the actual required synchronization.
>> void AcquireGlobal(ThreadState *thr, uptr pc);
>> void Release(ThreadState *thr, uptr pc, uptr addr);
>> +void ReleaseStoreAcquire(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 ReleaseStoreAcquireImpl(ThreadState *thr, uptr pc, SyncClock *c);
>> void ReleaseStoreImpl(ThreadState *thr, uptr pc, SyncClock *c);
>> void AcquireReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c);
>>
>> diff --git a/libsanitizer/tsan/tsan_rtl_mutex.cpp
>> b/libsanitizer/tsan/tsan_rtl_mutex.cpp
>> index ce6e7cb2c4e..ebd0d722181 100644
>> --- a/libsanitizer/tsan/tsan_rtl_mutex.cpp
>> +++ b/libsanitizer/tsan/tsan_rtl_mutex.cpp
>> @@ -415,8 +415,10 @@ static void
>> UpdateClockCallback(ThreadContextBase *tctx_base, void *arg) {
>> ThreadState *thr = reinterpret_cast<ThreadState*>(arg);
>> ThreadContext *tctx = static_cast<ThreadContext*>(tctx_base);
>> u64 epoch = tctx->epoch1;
>> - if (tctx->status == ThreadStatusRunning)
>> + if (tctx->status == ThreadStatusRunning) {
>> epoch = tctx->thr->fast_state.epoch();
>> + tctx->thr->clock.NoteGlobalAcquire(epoch);
>> + }
>> thr->clock.set(&thr->proc()->clock_cache, tctx->tid, epoch);
>> }
>>
>> @@ -429,6 +431,18 @@ void AcquireGlobal(ThreadState *thr, uptr pc) {
>> UpdateClockCallback, thr);
>> }
>>
>> +void ReleaseStoreAcquire(ThreadState *thr, uptr pc, uptr addr) {
>> + DPrintf("#%d: ReleaseStoreAcquire %zx\n", thr->tid, addr);
>> + if (thr->ignore_sync)
>> + return;
>> + SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true);
>> + thr->fast_state.IncrementEpoch();
>> + // Can't increment epoch w/o writing to the trace as well.
>> + TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0);
>> + ReleaseStoreAcquireImpl(thr, pc, &s->clock);
>> + s->mtx.Unlock();
>> +}
>> +
>> void Release(ThreadState *thr, uptr pc, uptr addr) {
>> DPrintf("#%d: Release %zx\n", thr->tid, addr);
>> if (thr->ignore_sync)
>> @@ -482,6 +496,15 @@ void AcquireImpl(ThreadState *thr, uptr pc,
>> SyncClock *c) {
>> StatInc(thr, StatSyncAcquire);
>> }
>>
>> +void ReleaseStoreAcquireImpl(ThreadState *thr, uptr pc, SyncClock *c) {
>> + if (thr->ignore_sync)
>> + return;
>> + thr->clock.set(thr->fast_state.epoch());
>> + thr->fast_synch_epoch = thr->fast_state.epoch();
>> + thr->clock.releaseStoreAcquire(&thr->proc()->clock_cache, c);
>> + StatInc(thr, StatSyncReleaseStoreAcquire);
>> +}
>> +
>> void ReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c) {
>> if (thr->ignore_sync)
>> return;
>> diff --git a/libsanitizer/tsan/tsan_rtl_ppc64.S
>> b/libsanitizer/tsan/tsan_rtl_ppc64.S
>> index 9e533a71a9c..8285e21aa1e 100644
>> --- a/libsanitizer/tsan/tsan_rtl_ppc64.S
>> +++ b/libsanitizer/tsan/tsan_rtl_ppc64.S
>> @@ -1,6 +1,5 @@
>> #include "tsan_ppc_regs.h"
>>
>> - .machine altivec
>> .section .text
>> .hidden __tsan_setjmp
>> .globl _setjmp
>> diff --git a/libsanitizer/tsan/tsan_rtl_thread.cpp
>> b/libsanitizer/tsan/tsan_rtl_thread.cpp
>> index 0ac1ee99c47..d80146735ea 100644
>> --- a/libsanitizer/tsan/tsan_rtl_thread.cpp
>> +++ b/libsanitizer/tsan/tsan_rtl_thread.cpp
>> @@ -144,6 +144,9 @@ void ThreadContext::OnFinished() {
>> thr->clock.ResetCached(&thr->proc()->clock_cache);
>> #if !SANITIZER_GO
>> thr->last_sleep_clock.ResetCached(&thr->proc()->clock_cache);
>> +#endif
>> +#if !SANITIZER_GO
>> + PlatformCleanUpThreadState(thr);
>> #endif
>> thr->~ThreadState();
>> #if TSAN_COLLECT_STATS
>> @@ -285,19 +288,34 @@ void ThreadFinish(ThreadState *thr) {
>> ctx->thread_registry->FinishThread(thr->tid);
>> }
>>
>> -static bool FindThreadByUid(ThreadContextBase *tctx, void *arg) {
>> - uptr uid = (uptr)arg;
>> - if (tctx->user_id == uid && tctx->status != ThreadStatusInvalid) {
>> +struct ConsumeThreadContext {
>> + uptr uid;
>> + ThreadContextBase *tctx;
>> +};
>> +
>> +static bool ConsumeThreadByUid(ThreadContextBase *tctx, void *arg) {
>> + ConsumeThreadContext *findCtx = (ConsumeThreadContext *)arg;
>> + if (tctx->user_id == findCtx->uid && tctx->status !=
>> ThreadStatusInvalid) {
>> + if (findCtx->tctx) {
>> + // Ensure that user_id is unique. If it's not the case we are
>> screwed.
>> + // Something went wrong before, but now there is no way to
>> recover.
>> + // Returning a wrong thread is not an option, it may lead to
>> very hard
>> + // to debug false positives (e.g. if we join a wrong thread).
>> + Report("ThreadSanitizer: dup thread with used id 0x%zx\n",
>> findCtx->uid);
>> + Die();
>> + }
>> + findCtx->tctx = tctx;
>> tctx->user_id = 0;
>> - return true;
>> }
>> return false;
>> }
>>
>> -int ThreadTid(ThreadState *thr, uptr pc, uptr uid) {
>> - int res = ctx->thread_registry->FindThread(FindThreadByUid,
>> (void*)uid);
>> - DPrintf("#%d: ThreadTid uid=%zu tid=%d\n", thr->tid, uid, res);
>> - return res;
>> +int ThreadConsumeTid(ThreadState *thr, uptr pc, uptr uid) {
>> + ConsumeThreadContext findCtx = {uid, nullptr};
>> + ctx->thread_registry->FindThread(ConsumeThreadByUid, &findCtx);
>> + int tid = findCtx.tctx ? findCtx.tctx->tid :
>> ThreadRegistry::kUnknownTid;
>> + DPrintf("#%d: ThreadTid uid=%zu tid=%d\n", thr->tid, uid, tid);
>> + return tid;
>> }
>>
>> void ThreadJoin(ThreadState *thr, uptr pc, int tid) {
>> diff --git a/libsanitizer/tsan/tsan_stat.h
>> b/libsanitizer/tsan/tsan_stat.h
>> index 94e18bc66df..8b26a59bb2e 100644
>> --- a/libsanitizer/tsan/tsan_stat.h
>> +++ b/libsanitizer/tsan/tsan_stat.h
>> @@ -68,6 +68,7 @@ enum StatType {
>> StatSyncDestroyed,
>> StatSyncAcquire,
>> StatSyncRelease,
>> + StatSyncReleaseStoreAcquire,
>>
>> // Clocks - acquire.
>> StatClockAcquire,
>> diff --git a/libsanitizer/ubsan/ubsan_checks.inc
>> b/libsanitizer/ubsan/ubsan_checks.inc
>> index 33a8dfcde02..2c1529a7d92 100644
>> --- a/libsanitizer/ubsan/ubsan_checks.inc
>> +++ b/libsanitizer/ubsan/ubsan_checks.inc
>> @@ -18,6 +18,8 @@
>>
>> UBSAN_CHECK(GenericUB, "undefined-behavior", "undefined")
>> UBSAN_CHECK(NullPointerUse, "null-pointer-use", "null")
>> +UBSAN_CHECK(NullPointerUseWithNullability, "null-pointer-use",
>> + "nullability-assign")
>> UBSAN_CHECK(NullptrWithOffset, "nullptr-with-offset",
>> "pointer-overflow")
>> UBSAN_CHECK(NullptrWithNonZeroOffset, "nullptr-with-nonzero-offset",
>> "pointer-overflow")
>> @@ -59,6 +61,10 @@ UBSAN_CHECK(InvalidEnumLoad, "invalid-enum-load",
>> "enum")
>> UBSAN_CHECK(FunctionTypeMismatch, "function-type-mismatch",
>> "function")
>> UBSAN_CHECK(InvalidNullReturn, "invalid-null-return",
>> "returns-nonnull-attribute")
>> +UBSAN_CHECK(InvalidNullReturnWithNullability, "invalid-null-return",
>> + "nullability-return")
>> UBSAN_CHECK(InvalidNullArgument, "invalid-null-argument",
>> "nonnull-attribute")
>> +UBSAN_CHECK(InvalidNullArgumentWithNullability,
>> "invalid-null-argument",
>> + "nullability-arg")
>> UBSAN_CHECK(DynamicTypeMismatch, "dynamic-type-mismatch", "vptr")
>> UBSAN_CHECK(CFIBadType, "cfi-bad-type", "cfi")
>> diff --git a/libsanitizer/ubsan/ubsan_flags.cpp
>> b/libsanitizer/ubsan/ubsan_flags.cpp
>> index 80de2a6d101..721c2273f13 100644
>> --- a/libsanitizer/ubsan/ubsan_flags.cpp
>> +++ b/libsanitizer/ubsan/ubsan_flags.cpp
>> @@ -54,7 +54,6 @@ void InitializeFlags() {
>> {
>> CommonFlags cf;
>> cf.CopyFrom(*common_flags());
>> - cf.print_summary = false;
>> cf.external_symbolizer_path = GetFlag("UBSAN_SYMBOLIZER_PATH");
>> OverrideCommonFlags(cf);
>> }
>> diff --git a/libsanitizer/ubsan/ubsan_handlers.cpp
>> b/libsanitizer/ubsan/ubsan_handlers.cpp
>> index 0ddbb50c26c..7f6a46fb6cf 100644
>> --- a/libsanitizer/ubsan/ubsan_handlers.cpp
>> +++ b/libsanitizer/ubsan/ubsan_handlers.cpp
>> @@ -36,6 +36,45 @@ bool ignoreReport(SourceLocation SLoc,
>> ReportOptions Opts, ErrorType ET) {
>> return SLoc.isDisabled() || IsPCSuppressed(ET, Opts.pc,
>> SLoc.getFilename());
>> }
>>
>> +/// Situations in which we might emit a check for the suitability of a
>> +/// pointer or glvalue. Needs to be kept in sync with
>> CodeGenFunction.h in
>> +/// clang.
>> +enum TypeCheckKind {
>> + /// Checking the operand of a load. Must be suitably sized and
>> aligned.
>> + TCK_Load,
>> + /// Checking the destination of a store. Must be suitably sized
>> and aligned.
>> + TCK_Store,
>> + /// Checking the bound value in a reference binding. Must be
>> suitably sized
>> + /// and aligned, but is not required to refer to an object (until the
>> + /// reference is used), per core issue 453.
>> + TCK_ReferenceBinding,
>> + /// Checking the object expression in a non-static data member
>> access. Must
>> + /// be an object within its lifetime.
>> + TCK_MemberAccess,
>> + /// Checking the 'this' pointer for a call to a non-static member
>> function.
>> + /// Must be an object within its lifetime.
>> + TCK_MemberCall,
>> + /// Checking the 'this' pointer for a constructor call.
>> + TCK_ConstructorCall,
>> + /// Checking the operand of a static_cast to a derived pointer
>> type. Must be
>> + /// null or an object within its lifetime.
>> + TCK_DowncastPointer,
>> + /// Checking the operand of a static_cast to a derived reference
>> type. Must
>> + /// be an object within its lifetime.
>> + TCK_DowncastReference,
>> + /// Checking the operand of a cast to a base object. Must be
>> suitably sized
>> + /// and aligned.
>> + TCK_Upcast,
>> + /// Checking the operand of a cast to a virtual base object. Must
>> be an
>> + /// object within its lifetime.
>> + TCK_UpcastToVirtualBase,
>> + /// Checking the value assigned to a _Nonnull pointer. Must not be
>> null.
>> + TCK_NonnullAssign,
>> + /// Checking the operand of a dynamic_cast or a typeid
>> expression. Must be
>> + /// null or an object within its lifetime.
>> + TCK_DynamicOperation
>> +};
>> +
>> const char *TypeCheckKinds[] = {
>> "load of", "store to", "reference binding to", "member access
>> within",
>> "member call on", "constructor call on", "downcast of",
>> "downcast of",
>> @@ -50,7 +89,9 @@ static void handleTypeMismatchImpl(TypeMismatchData
>> *Data, ValueHandle Pointer,
>> uptr Alignment = (uptr)1 << Data->LogAlignment;
>> ErrorType ET;
>> if (!Pointer)
>> - ET = ErrorType::NullPointerUse;
>> + ET = (Data->TypeCheckKind == TCK_NonnullAssign)
>> + ? ErrorType::NullPointerUseWithNullability
>> + : ErrorType::NullPointerUse;
>> else if (Pointer & (Alignment - 1))
>> ET = ErrorType::MisalignedPointerUse;
>> else
>> @@ -71,6 +112,7 @@ static void
>> handleTypeMismatchImpl(TypeMismatchData *Data, ValueHandle Pointer,
>>
>> switch (ET) {
>> case ErrorType::NullPointerUse:
>> + case ErrorType::NullPointerUseWithNullability:
>> Diag(Loc, DL_Error, ET, "%0 null pointer of type %1")
>> << TypeCheckKinds[Data->TypeCheckKind] << Data->Type;
>> break;
>> @@ -604,7 +646,8 @@ static void handleNonNullReturn(NonNullReturnData
>> *Data, SourceLocation *LocPtr,
>> UNREACHABLE("source location pointer is null!");
>>
>> SourceLocation Loc = LocPtr->acquire();
>> - ErrorType ET = ErrorType::InvalidNullReturn;
>> + ErrorType ET = IsAttr ? ErrorType::InvalidNullReturn
>> + : ErrorType::InvalidNullReturnWithNullability;
>>
>> if (ignoreReport(Loc, Opts, ET))
>> return;
>> @@ -648,7 +691,8 @@ void
>> __ubsan::__ubsan_handle_nullability_return_v1_abort(
>> static void handleNonNullArg(NonNullArgData *Data, ReportOptions Opts,
>> bool IsAttr) {
>> SourceLocation Loc = Data->Loc.acquire();
>> - ErrorType ET = ErrorType::InvalidNullArgument;
>> + ErrorType ET = IsAttr ? ErrorType::InvalidNullArgument
>> + :
>> ErrorType::InvalidNullArgumentWithNullability;
>>
>> if (ignoreReport(Loc, Opts, ET))
>> return;
>> @@ -819,21 +863,6 @@ void
>> __ubsan_handle_cfi_bad_type(CFICheckFailData *Data, ValueHandle Vtable,
>>
>> } // namespace __ubsan
>>
>> -void __ubsan::__ubsan_handle_cfi_bad_icall(CFIBadIcallData *CallData,
>> - ValueHandle Function) {
>> - GET_REPORT_OPTIONS(false);
>> - CFICheckFailData Data = {CFITCK_ICall, CallData->Loc,
>> CallData->Type};
>> - handleCFIBadIcall(&Data, Function, Opts);
>> -}
>> -
>> -void __ubsan::__ubsan_handle_cfi_bad_icall_abort(CFIBadIcallData
>> *CallData,
>> - ValueHandle
>> Function) {
>> - GET_REPORT_OPTIONS(true);
>> - CFICheckFailData Data = {CFITCK_ICall, CallData->Loc,
>> CallData->Type};
>> - handleCFIBadIcall(&Data, Function, Opts);
>> - Die();
>> -}
>> -
>> void __ubsan::__ubsan_handle_cfi_check_fail(CFICheckFailData *Data,
>> ValueHandle Value,
>> uptr ValidVtable) {
>> diff --git a/libsanitizer/ubsan/ubsan_handlers.h
>> b/libsanitizer/ubsan/ubsan_handlers.h
>> index eba1cf918fc..22ca9642238 100644
>> --- a/libsanitizer/ubsan/ubsan_handlers.h
>> +++ b/libsanitizer/ubsan/ubsan_handlers.h
>> @@ -207,20 +207,12 @@ enum CFITypeCheckKind : unsigned char {
>> CFITCK_VMFCall,
>> };
>>
>> -struct CFIBadIcallData {
>> - SourceLocation Loc;
>> - const TypeDescriptor &Type;
>> -};
>> -
>> struct CFICheckFailData {
>> CFITypeCheckKind CheckKind;
>> SourceLocation Loc;
>> const TypeDescriptor &Type;
>> };
>>
>> -/// \brief Handle control flow integrity failure for indirect
>> function calls.
>> -RECOVERABLE(cfi_bad_icall, CFIBadIcallData *Data, ValueHandle Function)
>> -
>> /// \brief Handle control flow integrity failures.
>> RECOVERABLE(cfi_check_fail, CFICheckFailData *Data, ValueHandle
>> Function,
>> uptr VtableIsValid)
>> diff --git a/libsanitizer/ubsan/ubsan_init.cpp
>> b/libsanitizer/ubsan/ubsan_init.cpp
>> index 1a3b7d37267..e0be5a72ec4 100644
>> --- a/libsanitizer/ubsan/ubsan_init.cpp
>> +++ b/libsanitizer/ubsan/ubsan_init.cpp
>> @@ -37,10 +37,12 @@ static void CommonStandaloneInit() {
>> SanitizerToolName = GetSanititizerToolName();
>> CacheBinaryName();
>> InitializeFlags();
>> + __sanitizer::InitializePlatformEarly();
>> __sanitizer_set_report_path(common_flags()->log_path);
>> AndroidLogInit();
>> InitializeCoverage(common_flags()->coverage,
>> common_flags()->coverage_dir);
>> CommonInit();
>> + Symbolizer::LateInitialize();
>> }
>>
>> void __ubsan::InitAsStandalone() {
>> diff --git a/libsanitizer/ubsan/ubsan_platform.h
>> b/libsanitizer/ubsan/ubsan_platform.h
>> index 58aabbe67b5..71d7fb18c9b 100644
>> --- a/libsanitizer/ubsan/ubsan_platform.h
>> +++ b/libsanitizer/ubsan/ubsan_platform.h
>> @@ -12,7 +12,6 @@
>> #ifndef UBSAN_PLATFORM_H
>> #define UBSAN_PLATFORM_H
>>
>> -#ifndef CAN_SANITIZE_UB
>> // Other platforms should be easy to add, and probably work as-is.
>> #if defined(__linux__) || defined(__FreeBSD__) ||
>> defined(__APPLE__) || \
>> defined(__NetBSD__) || defined(__OpenBSD__) || \
>> @@ -22,6 +21,5 @@
>> #else
>> # define CAN_SANITIZE_UB 0
>> #endif
>> -#endif //CAN_SANITIZE_UB
>>
>> #endif
>> diff --git a/libsanitizer/ubsan/ubsan_type_hash_itanium.cpp
>> b/libsanitizer/ubsan/ubsan_type_hash_itanium.cpp
>> index 97846d4dd43..4f1708ba190 100644
>> --- a/libsanitizer/ubsan/ubsan_type_hash_itanium.cpp
>> +++ b/libsanitizer/ubsan/ubsan_type_hash_itanium.cpp
>> @@ -16,6 +16,7 @@
>> #include "ubsan_type_hash.h"
>>
>> #include "sanitizer_common/sanitizer_common.h"
>> +#include "sanitizer_common/sanitizer_ptrauth.h"
>>
>> // The following are intended to be binary compatible with the
>> definitions
>> // given in the Itanium ABI. We make no attempt to be
>> ODR-compatible with
>> @@ -194,6 +195,7 @@ struct VtablePrefix {
>> std::type_info *TypeInfo;
>> };
>> VtablePrefix *getVtablePrefix(void *Vtable) {
>> + Vtable = ptrauth_auth_data(Vtable, ptrauth_key_cxx_vtable_pointer,
>> 0);
>> VtablePrefix *Vptr = reinterpret_cast<VtablePrefix*>(Vtable);
>> VtablePrefix *Prefix = Vptr - 1;
>> if (!IsAccessibleMemoryRange((uptr)Prefix, sizeof(VtablePrefix)))
>
>
-----------------
Mentor Graphics (Deutschland) GmbH, Arnulfstraße 201, 80634 München / Germany
Registergericht München HRB 106955, Geschäftsführer: Thomas Heurung, Alexander Walter
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH] Libsanitizer: merge from master.
2020-10-19 7:04 ` Tobias Burnus
@ 2020-10-19 7:11 ` Martin Liška
2020-10-19 7:39 ` Tobias Burnus
0 siblings, 1 reply; 17+ messages in thread
From: Martin Liška @ 2020-10-19 7:11 UTC (permalink / raw)
To: Tobias Burnus, gcc-patches
On 10/19/20 9:04 AM, Tobias Burnus wrote:
> Hi Martin,
Hello.
>
> this patch caused here a build fail:
>
> gcc-mainline/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp:490:39: error: 'NT_X86_XSTATE' was not declared in this scope
>
> It turned out that the used GLIBC of the cross build is 2.11.1.
> And that one does not contain this #define in 'elf.h'.
Thanks for the heads up.
>
> I wonder whether we should do something like the following – what do you think?
>
> --- a/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp
> @@ -490 +490,5 @@ typedef user_regs_struct regs_struct;
> -static constexpr uptr kExtraRegs[] = {NT_X86_XSTATE, NT_FPREGSET};
> +static constexpr uptr kExtraRegs[] = {
> +#ifdef NT_X86_XSTATE
> + NT_X86_XSTATE,
> +#endif
> + DNT_FPREGSET};
>
> Tobias
The change was introduced in the upstream commit:
https://github.com/llvm/llvm-project/commit/5813fca1076089c835de737834955a0fe7eb3898
Please create a LLVM bugzilla entry where you can mention that and they will
hopefully merge the change. We usually upstream the changes first.
Thanks,
Martin
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH] Libsanitizer: merge from master.
2020-10-19 7:11 ` Martin Liška
@ 2020-10-19 7:39 ` Tobias Burnus
2020-10-20 8:09 ` Tobias Burnus
0 siblings, 1 reply; 17+ messages in thread
From: Tobias Burnus @ 2020-10-19 7:39 UTC (permalink / raw)
To: Martin Liška, gcc-patches
On 10/19/20 9:11 AM, Martin Liška wrote:
> The change was introduced in the upstream commit:
> https://github.com/llvm/llvm-project/commit/5813fca1076089c835de737834955a0fe7eb3898
>
>
> Please create a LLVM bugzilla entry where you can mention that
Filled as https://bugs.llvm.org/show_bug.cgi?id=47896
Tobias
-----------------
Mentor Graphics (Deutschland) GmbH, Arnulfstraße 201, 80634 München / Germany
Registergericht München HRB 106955, Geschäftsführer: Thomas Heurung, Alexander Walter
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH] Libsanitizer: merge from master.
2020-10-19 7:39 ` Tobias Burnus
@ 2020-10-20 8:09 ` Tobias Burnus
2020-10-20 9:16 ` Martin Liška
0 siblings, 1 reply; 17+ messages in thread
From: Tobias Burnus @ 2020-10-20 8:09 UTC (permalink / raw)
To: Martin Liška, gcc-patches
[-- Attachment #1: Type: text/plain, Size: 604 bytes --]
On 10/19/20 9:39 AM, Tobias Burnus wrote:
> Filled as https://bugs.llvm.org/show_bug.cgi?id=47896
That issue was fixed. What's the proper way to apply this patch? Simply
committing the attached patch* or is there more required?
Tobias
*Namely, from LLVM: git diff 51ff04567b2f8d06b2062bd3ed72eab2e93e4466..
compiler-rt/lib/sanitizer_common/; I ignored the changes in
compiler-rt/lib/{gwp_asan,memprof}.
-----------------
Mentor Graphics (Deutschland) GmbH, Arnulfstraße 201, 80634 München / Germany
Registergericht München HRB 106955, Geschäftsführer: Thomas Heurung, Alexander Walter
[-- Attachment #2: fix-san.diff --]
[-- Type: text/x-patch, Size: 6496 bytes --]
libsanitizer: merge from master
libsanitizer/MERGE | 2 +-
libsanitizer/sanitizer_common/sanitizer_allocator_report.cpp | 8 ++++++++
libsanitizer/sanitizer_common/sanitizer_allocator_report.h | 1 +
libsanitizer/sanitizer_common/sanitizer_flags.inc | 5 +++--
libsanitizer/sanitizer_common/sanitizer_internal_defs.h | 3 +++
libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp | 7 ++-----
.../sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp | 4 ++++
libsanitizer/sanitizer_common/sanitizer_tls_get_addr.cpp | 7 ++++++-
8 files changed, 28 insertions(+), 9 deletions(-)
diff --git a/libsanitizer/MERGE b/libsanitizer/MERGE
index d2a25927007..f9657fc6728 100644
--- a/libsanitizer/MERGE
+++ b/libsanitizer/MERGE
@@ -1,4 +1,4 @@
-51ff04567b2f8d06b2062bd3ed72eab2e93e4466
+f97ca48b1cbbf5da065e94271cb3af4f1c907dd4
The first line of this file holds the git revision number of the
last merge done from the master library sources.
diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_report.cpp b/libsanitizer/sanitizer_common/sanitizer_allocator_report.cpp
index d74e08010d5..1c6520819ef 100644
--- a/libsanitizer/sanitizer_common/sanitizer_allocator_report.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_allocator_report.cpp
@@ -134,4 +134,12 @@ void NORETURN ReportOutOfMemory(uptr requested_size, const StackTrace *stack) {
Die();
}
+void NORETURN ReportRssLimitExceeded(const StackTrace *stack) {
+ {
+ ScopedAllocatorErrorReport report("rss-limit-exceeded", stack);
+ Report("ERROR: %s: allocator exceeded the RSS limit\n", SanitizerToolName);
+ }
+ Die();
+}
+
} // namespace __sanitizer
diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_report.h b/libsanitizer/sanitizer_common/sanitizer_allocator_report.h
index 0653c365c1c..6e4e6b13549 100644
--- a/libsanitizer/sanitizer_common/sanitizer_allocator_report.h
+++ b/libsanitizer/sanitizer_common/sanitizer_allocator_report.h
@@ -33,6 +33,7 @@ void NORETURN ReportInvalidPosixMemalignAlignment(uptr alignment,
void NORETURN ReportAllocationSizeTooBig(uptr user_size, uptr max_size,
const StackTrace *stack);
void NORETURN ReportOutOfMemory(uptr requested_size, const StackTrace *stack);
+void NORETURN ReportRssLimitExceeded(const StackTrace *stack);
} // namespace __sanitizer
diff --git a/libsanitizer/sanitizer_common/sanitizer_flags.inc b/libsanitizer/sanitizer_common/sanitizer_flags.inc
index d1412478fd2..d8e809b0609 100644
--- a/libsanitizer/sanitizer_common/sanitizer_flags.inc
+++ b/libsanitizer/sanitizer_common/sanitizer_flags.inc
@@ -82,8 +82,9 @@ COMMON_FLAG(bool, print_summary, true,
"If false, disable printing error summaries in addition to error "
"reports.")
COMMON_FLAG(int, print_module_map, 0,
- "OS X only (0 - don't print, 1 - print only once before process "
- "exits, 2 - print after each report).")
+ "Print the process module map where supported (0 - don't print, "
+ "1 - print only once before process exits, 2 - print after each "
+ "report).")
COMMON_FLAG(bool, check_printf, true, "Check printf arguments.")
#define COMMON_FLAG_HANDLE_SIGNAL_HELP(signal) \
"Controls custom tool's " #signal " handler (0 - do not registers the " \
diff --git a/libsanitizer/sanitizer_common/sanitizer_internal_defs.h b/libsanitizer/sanitizer_common/sanitizer_internal_defs.h
index a6c55148705..8b34e54137d 100644
--- a/libsanitizer/sanitizer_common/sanitizer_internal_defs.h
+++ b/libsanitizer/sanitizer_common/sanitizer_internal_defs.h
@@ -448,5 +448,8 @@ using namespace __sanitizer;
namespace __hwasan {
using namespace __sanitizer;
}
+namespace __memprof {
+using namespace __sanitizer;
+}
#endif // SANITIZER_DEFS_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp
index af077439478..2bd5564ae05 100644
--- a/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp
@@ -385,12 +385,9 @@ uptr ThreadSelf() {
descr_addr = reinterpret_cast<uptr>(__builtin_thread_pointer()) -
ThreadDescriptorSize();
#elif SANITIZER_RISCV64
- uptr tcb_end;
- asm volatile("mv %0, tp;\n" : "=r"(tcb_end));
// https://github.com/riscv/riscv-elf-psabi-doc/issues/53
- const uptr kTlsTcbOffset = 0x800;
- descr_addr =
- reinterpret_cast<uptr>(tcb_end - kTlsTcbOffset - TlsPreTcbSize());
+ uptr thread_pointer = reinterpret_cast<uptr>(__builtin_thread_pointer());
+ descr_addr = thread_pointer - TlsPreTcbSize();
#elif defined(__s390__)
descr_addr = reinterpret_cast<uptr>(__builtin_thread_pointer());
#elif defined(__powerpc64__)
diff --git a/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp
index 6a3c00458ef..eb89f1fddc5 100644
--- a/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp
@@ -486,6 +486,10 @@ typedef user_regs_struct regs_struct;
#define REG_SP rsp
#endif
#define ARCH_IOVEC_FOR_GETREGSET
+// Support ptrace extensions even when compiled without required kernel support
+#ifndef NT_X86_XSTATE
+#define NT_X86_XSTATE 0x202
+#endif
// Compiler may use FP registers to store pointers.
static constexpr uptr kExtraRegs[] = {NT_X86_XSTATE, NT_FPREGSET};
diff --git a/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.cpp b/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.cpp
index 9ca898a306a..10748f96420 100644
--- a/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.cpp
@@ -80,8 +80,13 @@ void DTLS_Destroy() {
#if defined(__powerpc64__) || defined(__mips__)
// This is glibc's TLS_DTV_OFFSET:
// "Dynamic thread vector pointers point 0x8000 past the start of each
-// TLS block."
+// TLS block." (sysdeps/<arch>/dl-tls.h)
static const uptr kDtvOffset = 0x8000;
+#elif defined(__riscv)
+// This is glibc's TLS_DTV_OFFSET:
+// "Dynamic thread vector pointers point 0x800 past the start of each
+// TLS block." (sysdeps/riscv/dl-tls.h)
+static const uptr kDtvOffset = 0x800;
#else
static const uptr kDtvOffset = 0;
#endif
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH] Libsanitizer: merge from master.
2020-10-20 8:09 ` Tobias Burnus
@ 2020-10-20 9:16 ` Martin Liška
0 siblings, 0 replies; 17+ messages in thread
From: Martin Liška @ 2020-10-20 9:16 UTC (permalink / raw)
To: Tobias Burnus, gcc-patches
On 10/20/20 10:09 AM, Tobias Burnus wrote:
> On 10/19/20 9:39 AM, Tobias Burnus wrote:
>> Filled as https://bugs.llvm.org/show_bug.cgi?id=47896
>
> That issue was fixed. What's the proper way to apply this patch? Simply
> committing the attached patch* or is there more required?
We normally do only a cherry-pick. I've just did so and pushed the commit.
Typically you don't want to do a merge and process all steps mentioned in
libsanitizer/HOWTO_MERGE.
Thanks,
Martin
>
> Tobias
>
> *Namely, from LLVM: git diff 51ff04567b2f8d06b2062bd3ed72eab2e93e4466..
> compiler-rt/lib/sanitizer_common/; I ignored the changes in
> compiler-rt/lib/{gwp_asan,memprof}.
>
> -----------------
> Mentor Graphics (Deutschland) GmbH, Arnulfstraße 201, 80634 München / Germany
> Registergericht München HRB 106955, Geschäftsführer: Thomas Heurung, Alexander Walter
^ permalink raw reply [flat|nested] 17+ messages in thread
end of thread, other threads:[~2021-06-04 7:50 UTC | newest]
Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-05-13 7:28 [PATCH] libsanitizer: merge from master Martin Liška
2021-05-13 15:54 ` H.J. Lu
2021-05-13 17:27 ` Martin Liška
2021-05-13 20:01 ` H.J. Lu
2021-05-13 20:11 ` H.J. Lu
2021-05-14 1:26 ` [PATCH] libsanitizer: cherry-pick from upstream H.J. Lu
2021-06-04 7:32 ` [PATCH] libsanitizer: merge from master Hongtao Liu
2021-06-04 7:36 ` Martin Liška
2021-06-04 7:53 ` Hongtao Liu
-- strict thread matches above, loose matches on Subject: below --
2020-06-02 6:00 [PATCH] Libsanitizer: " Martin Liška
2020-06-06 19:47 ` Andreas Schwab
2020-10-16 8:59 ` Martin Liška
2020-10-19 7:04 ` Tobias Burnus
2020-10-19 7:11 ` Martin Liška
2020-10-19 7:39 ` Tobias Burnus
2020-10-20 8:09 ` Tobias Burnus
2020-10-20 9:16 ` Martin Liška
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).