Libsanitizer: merge from master.
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.
This commit is contained in:
parent
2b11374cb8
commit
3c6331c29f
107 changed files with 2543 additions and 762 deletions
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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); \
|
||||
|
|
|
@ -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);
|
||||
|
@ -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;
|
||||
static void ClassifyAllChunks(SuspendedThreadsList const &suspended_threads,
|
||||
Frontier *frontier) {
|
||||
ForEachChunk(CollectIgnoredCb, frontier);
|
||||
ProcessGlobalRegions(frontier);
|
||||
ProcessThreads(suspended_threads, frontier);
|
||||
ProcessRootRegions(frontier);
|
||||
FloodFillTag(frontier, kReachable);
|
||||
|
||||
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) {
|
||||
|
|
|
@ -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
|
||||
|
|
166
libsanitizer/lsan/lsan_common_fuchsia.cpp
Normal file
166
libsanitizer/lsan/lsan_common_fuchsia.cpp
Normal file
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
123
libsanitizer/lsan/lsan_fuchsia.cpp
Normal file
123
libsanitizer/lsan/lsan_fuchsia.cpp
Normal file
|
@ -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
|
35
libsanitizer/lsan/lsan_fuchsia.h
Normal file
35
libsanitizer/lsan/lsan_fuchsia.h
Normal file
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
96
libsanitizer/lsan/lsan_posix.cpp
Normal file
96
libsanitizer/lsan/lsan_posix.cpp
Normal file
|
@ -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
|
49
libsanitizer/lsan/lsan_posix.h
Normal file
49
libsanitizer/lsan/lsan_posix.h
Normal file
|
@ -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
|
|
@ -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) {}
|
||||
ThreadContextLsanBase::ThreadContextLsanBase(int tid)
|
||||
: ThreadContextBase(tid) {}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
void InitializeThreadRegistry();
|
||||
// This subclass of ThreadContextLsanBase is declared in an OS-specific header.
|
||||
class ThreadContext;
|
||||
|
||||
void ThreadStart(u32 tid, tid_t os_id,
|
||||
ThreadType thread_type = ThreadType::Regular);
|
||||
void InitializeThreadRegistry();
|
||||
void InitializeMainThread();
|
||||
|
||||
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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(); }
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 <dirent.h>
|
||||
#include <fts.h>
|
||||
#include <fstab.h>
|
||||
#include <grp.h>
|
||||
#include <limits.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 <dlfcn.h>
|
||||
#include <fstab.h>
|
||||
#include <fts.h>
|
||||
#include <glob.h>
|
||||
#include <grp.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <limits.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);
|
||||
void *__sanitizer_get_link_map_by_dlopen_handle(void *handle) {
|
||||
void *p = nullptr;
|
||||
return internal_dlinfo(handle, RTLD_DI_LINKMAP, &p) == 0 ? p : nullptr;
|
||||
}
|
||||
|
||||
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;
|
||||
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);
|
||||
|
||||
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);
|
||||
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 map_fixed = MAP_FIXED;
|
||||
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 af_inet = (int)AF_INET;
|
||||
int af_inet6 = (int)AF_INET6;
|
||||
int map_fixed = MAP_FIXED;
|
||||
|
||||
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;
|
||||
}
|
||||
int af_inet = (int)AF_INET;
|
||||
int af_inet6 = (int)AF_INET6;
|
||||
|
||||
unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
|
||||
int glob_nomatch = GLOB_NOMATCH;
|
||||
int glob_altdirfunc = GLOB_ALTDIRFUNC;
|
||||
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 path_max = PATH_MAX;
|
||||
unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
|
||||
int glob_nomatch = GLOB_NOMATCH;
|
||||
int glob_altdirfunc = GLOB_ALTDIRFUNC;
|
||||
|
||||
// ioctl arguments
|
||||
unsigned struct_ifreq_sz = sizeof(struct ifreq);
|
||||
unsigned struct_termios_sz = sizeof(struct termios);
|
||||
unsigned struct_winsize_sz = sizeof(struct winsize);
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
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
|
||||
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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
80
libsanitizer/sanitizer_common/sanitizer_procmaps_fuchsia.cpp
Normal file
80
libsanitizer/sanitizer_common/sanitizer_procmaps_fuchsia.cpp
Normal file
|
@ -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
|
21
libsanitizer/sanitizer_common/sanitizer_ptrauth.h
Normal file
21
libsanitizer/sanitizer_common/sanitizer_ptrauth.h
Normal file
|
@ -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
|
|
@ -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))
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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.
|
||||
|
|
|
@ -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_);
|
||||
|
|
|
@ -126,4 +126,10 @@ Symbolizer::SymbolizerScope::~SymbolizerScope() {
|
|||
sym_->end_hook_();
|
||||
}
|
||||
|
||||
void Symbolizer::LateInitializeTools() {
|
||||
for (auto &tool : tools_) {
|
||||
tool.LateInitialize();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace __sanitizer
|
||||
|
|
|
@ -209,6 +209,9 @@ class Symbolizer final {
|
|||
private:
|
||||
const Symbolizer *sym_;
|
||||
};
|
||||
|
||||
// Calls `LateInitialize()` on all items in `tools_`.
|
||||
void LateInitializeTools();
|
||||
};
|
||||
|
||||
#ifdef SANITIZER_WINDOWS
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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_;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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_;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -310,7 +310,7 @@ Symbolizer *Symbolizer::PlatformInit() {
|
|||
}
|
||||
|
||||
void Symbolizer::LateInitialize() {
|
||||
Symbolizer::GetOrInit();
|
||||
Symbolizer::GetOrInit()->LateInitializeTools();
|
||||
}
|
||||
|
||||
} // namespace __sanitizer
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#include "tsan_ppc_regs.h"
|
||||
|
||||
.machine altivec
|
||||
.section .text
|
||||
.hidden __tsan_setjmp
|
||||
.globl _setjmp
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -68,6 +68,7 @@ enum StatType {
|
|||
StatSyncDestroyed,
|
||||
StatSyncAcquire,
|
||||
StatSyncRelease,
|
||||
StatSyncReleaseStoreAcquire,
|
||||
|
||||
// Clocks - acquire.
|
||||
StatClockAcquire,
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue