Summary: We were not following the `man` documented behaviors for invalid arguments to `memalign` and associated functions. Using `CHECK` for those was a bit extreme, so we relax the behavior to return null pointers as expected when this happens. Adapt the associated test. I am using this change also to change a few more minor performance improvements: - mark as `UNLIKELY` a bunch of unlikely conditions; - the current `CHECK` in `__sanitizer::RoundUpTo` is redundant for us in *all* calls. So I am introducing our own version without said `CHECK`. - change our combined allocator `GetActuallyAllocatedSize`. We already know if the pointer is from the Primary or Secondary, so the `PointerIsMine` check is redundant as well, and costly for the 32-bit Primary. So we get the size by directly using the available Primary functions. Finally, change a `int` to `uptr` to avoid a warning/error when compiling on Android. Reviewers: alekseyshl Reviewed By: alekseyshl Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D34782 llvm-svn: 306698
96 lines
3.3 KiB
C++
96 lines
3.3 KiB
C++
//===-- scudo_tls_android.cpp -----------------------------------*- C++ -*-===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
///
|
|
/// Scudo thread local structure implementation for Android.
|
|
///
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "sanitizer_common/sanitizer_platform.h"
|
|
|
|
#if SANITIZER_LINUX && SANITIZER_ANDROID
|
|
|
|
#include "scudo_tls.h"
|
|
|
|
#include <pthread.h>
|
|
|
|
namespace __scudo {
|
|
|
|
static pthread_once_t GlobalInitialized = PTHREAD_ONCE_INIT;
|
|
static pthread_key_t PThreadKey;
|
|
|
|
static atomic_uint32_t ThreadContextCurrentIndex;
|
|
static ScudoThreadContext *ThreadContexts;
|
|
static uptr NumberOfContexts;
|
|
|
|
// sysconf(_SC_NPROCESSORS_{CONF,ONLN}) cannot be used as they allocate memory.
|
|
static uptr getNumberOfCPUs() {
|
|
cpu_set_t CPUs;
|
|
CHECK_EQ(sched_getaffinity(0, sizeof(cpu_set_t), &CPUs), 0);
|
|
return CPU_COUNT(&CPUs);
|
|
}
|
|
|
|
static void initOnce() {
|
|
// Hack: TLS_SLOT_TSAN was introduced in N. To be able to use it on M for
|
|
// testing, we create an unused key. Since the key_data array follows the tls
|
|
// array, it basically gives us the extra entry we need.
|
|
// TODO(kostyak): remove and restrict to N and above.
|
|
CHECK_EQ(pthread_key_create(&PThreadKey, NULL), 0);
|
|
initScudo();
|
|
NumberOfContexts = getNumberOfCPUs();
|
|
ThreadContexts = reinterpret_cast<ScudoThreadContext *>(
|
|
MmapOrDie(sizeof(ScudoThreadContext) * NumberOfContexts, __func__));
|
|
for (uptr i = 0; i < NumberOfContexts; i++)
|
|
ThreadContexts[i].init();
|
|
}
|
|
|
|
void initThread() {
|
|
pthread_once(&GlobalInitialized, initOnce);
|
|
// Initial context assignment is done in a plain round-robin fashion.
|
|
u32 Index = atomic_fetch_add(&ThreadContextCurrentIndex, 1,
|
|
memory_order_relaxed);
|
|
ScudoThreadContext *ThreadContext =
|
|
&ThreadContexts[Index % NumberOfContexts];
|
|
*get_android_tls_ptr() = reinterpret_cast<uptr>(ThreadContext);
|
|
}
|
|
|
|
ScudoThreadContext *getThreadContextAndLockSlow() {
|
|
ScudoThreadContext *ThreadContext;
|
|
// Go through all the contexts and find the first unlocked one.
|
|
for (u32 i = 0; i < NumberOfContexts; i++) {
|
|
ThreadContext = &ThreadContexts[i];
|
|
if (ThreadContext->tryLock()) {
|
|
*get_android_tls_ptr() = reinterpret_cast<uptr>(ThreadContext);
|
|
return ThreadContext;
|
|
}
|
|
}
|
|
// No luck, find the one with the lowest precedence, and slow lock it.
|
|
u64 Precedence = UINT64_MAX;
|
|
for (u32 i = 0; i < NumberOfContexts; i++) {
|
|
u64 SlowLockPrecedence = ThreadContexts[i].getSlowLockPrecedence();
|
|
if (SlowLockPrecedence && SlowLockPrecedence < Precedence) {
|
|
ThreadContext = &ThreadContexts[i];
|
|
Precedence = SlowLockPrecedence;
|
|
}
|
|
}
|
|
if (LIKELY(Precedence != UINT64_MAX)) {
|
|
ThreadContext->lock();
|
|
*get_android_tls_ptr() = reinterpret_cast<uptr>(ThreadContext);
|
|
return ThreadContext;
|
|
}
|
|
// Last resort (can this happen?), stick with the current one.
|
|
ThreadContext =
|
|
reinterpret_cast<ScudoThreadContext *>(*get_android_tls_ptr());
|
|
ThreadContext->lock();
|
|
return ThreadContext;
|
|
}
|
|
|
|
} // namespace __scudo
|
|
|
|
#endif // SANITIZER_LINUX && SANITIZER_ANDROID
|