forked from OSchip/llvm-project
[lsan] Support LeakSanitizer runtime on Fuchsia
Support LeakSanitizer runtime on Fuchsia. Patch By: mcgrathr Differential Revision: https://reviews.llvm.org/D72887
This commit is contained in:
parent
b276dec5b6
commit
d59e3429f3
|
@ -640,7 +640,7 @@ else()
|
|||
endif()
|
||||
|
||||
if (COMPILER_RT_HAS_SANITIZER_COMMON AND LSAN_SUPPORTED_ARCH AND
|
||||
OS_NAME MATCHES "Darwin|Linux|NetBSD")
|
||||
OS_NAME MATCHES "Darwin|Linux|NetBSD|Fuchsia")
|
||||
set(COMPILER_RT_HAS_LSAN TRUE)
|
||||
else()
|
||||
set(COMPILER_RT_HAS_LSAN FALSE)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -5,6 +5,7 @@ append_rtti_flag(OFF LSAN_CFLAGS)
|
|||
|
||||
set(LSAN_COMMON_SOURCES
|
||||
lsan_common.cpp
|
||||
lsan_common_fuchsia.cpp
|
||||
lsan_common_linux.cpp
|
||||
lsan_common_mac.cpp
|
||||
)
|
||||
|
@ -12,6 +13,7 @@ set(LSAN_COMMON_SOURCES
|
|||
set(LSAN_SOURCES
|
||||
lsan.cpp
|
||||
lsan_allocator.cpp
|
||||
lsan_fuchsia.cpp
|
||||
lsan_interceptors.cpp
|
||||
lsan_linux.cpp
|
||||
lsan_mac.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)
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
#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"
|
||||
|
@ -36,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); \
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
@ -531,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());
|
||||
|
@ -543,6 +560,8 @@ static void ReportUnsuspendedThreads(
|
|||
&ReportIfNotSuspended, &threads);
|
||||
}
|
||||
|
||||
#endif // !SANITIZER_FUCHSIA
|
||||
|
||||
static void CheckForLeaksCallback(const SuspendedThreadsList &suspended_threads,
|
||||
void *arg) {
|
||||
CheckForLeaksParam *param = reinterpret_cast<CheckForLeaksParam *>(arg);
|
||||
|
|
|
@ -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
|
||||
|
@ -223,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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -63,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;
|
||||
|
@ -74,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);
|
||||
|
@ -102,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) {
|
||||
|
@ -309,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) {
|
||||
|
@ -396,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;
|
||||
|
@ -478,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);
|
||||
|
@ -516,6 +526,8 @@ void InitializeInterceptors() {
|
|||
Die();
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // !SANITIZER_FUCHSIA
|
||||
}
|
||||
|
||||
} // namespace __lsan
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -35,6 +35,7 @@ set(SANITIZER_SOURCES_NOTERMINATION
|
|||
sanitizer_procmaps_solaris.cpp
|
||||
sanitizer_rtems.cpp
|
||||
sanitizer_solaris.cpp
|
||||
sanitizer_stoptheworld_fuchsia.cpp
|
||||
sanitizer_stoptheworld_mac.cpp
|
||||
sanitizer_suppressions.cpp
|
||||
sanitizer_tls_get_addr.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
|
Loading…
Reference in New Issue