libtsan: update to LLVM 21

This commit is contained in:
Alex Rønne Petersen 2025-07-16 11:22:46 +02:00
parent 85438e75e0
commit ac20506090
No known key found for this signature in database
58 changed files with 1891 additions and 835 deletions

View file

@ -61,7 +61,7 @@
#define LOCAL_LABEL(name) .L ## name
#define FILE_LEVEL_DIRECTIVE
#define SYMBOL_IS_FUNC(name) \
.def name SEPARATOR \
.def FUNC_SYMBOL(name) SEPARATOR \
.scl 2 SEPARATOR \
.type 32 SEPARATOR \
.endef
@ -71,7 +71,7 @@
#endif
#if defined(__arm__) || defined(__aarch64__)
#if defined(__arm__) || defined(__aarch64__) || defined(__arm64ec__)
#define FUNC_ALIGN \
.text SEPARATOR \
.balign 16 SEPARATOR
@ -194,6 +194,23 @@
#else
#define WIDE(op) op
#endif
#if defined(__ARM_FEATURE_PAC_DEFAULT) && defined(__ARM_FEATURE_BTI_DEFAULT)
#define PACBTI_LANDING pacbti r12, lr, sp
#elif defined(__ARM_FEATURE_PAC_DEFAULT)
#define PACBTI_LANDING pac r12, lr, sp
#elif defined(__ARM_FEATURE_BTI_DEFAULT)
#define PACBTI_LANDING bti
#else
#define PACBTI_LANDING
#endif
#if defined(__ARM_FEATURE_PAUTH)
#define PAC_RETURN bxaut r12, lr, sp
#else
#define PAC_RETURN aut r12, lr, sp SEPARATOR bx lr
#endif
#else // !defined(__arm)
#define DECLARE_FUNC_ENCODING
#define DEFINE_CODE_STATE
@ -208,6 +225,16 @@
#define GLUE4(a, b, c, d) GLUE4_(a, b, c, d)
#define SYMBOL_NAME(name) GLUE(__USER_LABEL_PREFIX__, name)
#ifndef __arm64ec__
#define FUNC_SYMBOL(name) name
#else
// On ARM64EC, function names and calls (but not address-taking or data symbol
// references) use symbols prefixed with "#".
#define QUOTE(a) #a
#define STR(a) QUOTE(a)
#define HASH #
#define FUNC_SYMBOL(name) STR(GLUE2(HASH, name))
#endif
#ifdef VISIBILITY_HIDDEN
#define DECLARE_SYMBOL_VISIBILITY(name) \
@ -222,54 +249,54 @@
#define DEFINE_COMPILERRT_FUNCTION(name) \
DEFINE_CODE_STATE \
FILE_LEVEL_DIRECTIVE SEPARATOR \
.globl SYMBOL_NAME(name) SEPARATOR \
.globl FUNC_SYMBOL(SYMBOL_NAME(name)) SEPARATOR \
SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \
DECLARE_SYMBOL_VISIBILITY(name) \
DECLARE_FUNC_ENCODING \
SYMBOL_NAME(name):
FUNC_SYMBOL(SYMBOL_NAME(name)):
#define DEFINE_COMPILERRT_THUMB_FUNCTION(name) \
DEFINE_CODE_STATE \
FILE_LEVEL_DIRECTIVE SEPARATOR \
.globl SYMBOL_NAME(name) SEPARATOR \
.globl FUNC_SYMBOL(SYMBOL_NAME(name)) SEPARATOR \
SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \
DECLARE_SYMBOL_VISIBILITY(name) SEPARATOR \
.thumb_func SEPARATOR \
SYMBOL_NAME(name):
FUNC_SYMBOL(SYMBOL_NAME(name)):
#define DEFINE_COMPILERRT_PRIVATE_FUNCTION(name) \
DEFINE_CODE_STATE \
FILE_LEVEL_DIRECTIVE SEPARATOR \
.globl SYMBOL_NAME(name) SEPARATOR \
.globl FUNC_SYMBOL(SYMBOL_NAME(name)) SEPARATOR \
SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \
HIDDEN(SYMBOL_NAME(name)) SEPARATOR \
DECLARE_FUNC_ENCODING \
SYMBOL_NAME(name):
FUNC_SYMBOL(SYMBOL_NAME(name)):
#define DEFINE_COMPILERRT_PRIVATE_FUNCTION_UNMANGLED(name) \
DEFINE_CODE_STATE \
.globl name SEPARATOR \
.globl FUNC_SYMBOL(name) SEPARATOR \
SYMBOL_IS_FUNC(name) SEPARATOR \
HIDDEN(name) SEPARATOR \
DECLARE_FUNC_ENCODING \
name:
FUNC_SYMBOL(name):
#define DEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(name) \
DEFINE_CODE_STATE \
FUNC_ALIGN \
.globl name SEPARATOR \
.globl FUNC_SYMBOL(name) SEPARATOR \
SYMBOL_IS_FUNC(name) SEPARATOR \
DECLARE_SYMBOL_VISIBILITY_UNMANGLED(name) SEPARATOR \
DECLARE_SYMBOL_VISIBILITY_UNMANGLED(FUNC_SYMBOL(name)) SEPARATOR \
DECLARE_FUNC_ENCODING \
name: \
FUNC_SYMBOL(name): \
SEPARATOR CFI_START \
SEPARATOR BTI_C
#define DEFINE_COMPILERRT_FUNCTION_ALIAS(name, target) \
.globl SYMBOL_NAME(name) SEPARATOR \
.globl FUNC_SYMBOL(SYMBOL_NAME(name)) SEPARATOR \
SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \
DECLARE_SYMBOL_VISIBILITY(name) SEPARATOR \
.set SYMBOL_NAME(name), SYMBOL_NAME(target) SEPARATOR
.set FUNC_SYMBOL(SYMBOL_NAME(name)), FUNC_SYMBOL(target) SEPARATOR
#if defined(__ARM_EABI__)
#define DEFINE_AEABI_FUNCTION_ALIAS(aeabi_name, name) \

View file

@ -19,7 +19,7 @@
#if !SANITIZER_LINUX && !SANITIZER_FREEBSD && !SANITIZER_APPLE && \
!SANITIZER_NETBSD && !SANITIZER_WINDOWS && !SANITIZER_FUCHSIA && \
!SANITIZER_SOLARIS
!SANITIZER_SOLARIS && !SANITIZER_HAIKU && !SANITIZER_AIX
# error "Interception doesn't work on this operating system."
#endif
@ -168,6 +168,16 @@ const interpose_substitution substitution_##func_name[] \
extern "C" ret_type func(__VA_ARGS__);
# define DECLARE_WRAPPER_WINAPI(ret_type, func, ...) \
extern "C" __declspec(dllimport) ret_type __stdcall func(__VA_ARGS__);
#elif SANITIZER_AIX
# define WRAP(x) __interceptor_##x
# define TRAMPOLINE(x) WRAP(x)
// # define WRAPPER_NAME(x) "__interceptor_" #x
# define INTERCEPTOR_ATTRIBUTE __attribute__((visibility("default")))
// AIX's linker will not select the weak symbol, so don't use weak for the
// interceptors.
# define DECLARE_WRAPPER(ret_type, func, ...) \
extern "C" ret_type func(__VA_ARGS__) \
__attribute__((alias("__interceptor_" #func), visibility("default")));
#elif !SANITIZER_FUCHSIA // LINUX, FREEBSD, NETBSD, SOLARIS
# define INTERCEPTOR_ATTRIBUTE __attribute__((visibility("default")))
# if ASM_INTERCEPTOR_TRAMPOLINE_SUPPORT
@ -367,8 +377,13 @@ inline void DoesNotSupportStaticLinking() {}
#define INCLUDED_FROM_INTERCEPTION_LIB
#if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || \
SANITIZER_SOLARIS
#if SANITIZER_AIX
# include "interception_aix.h"
# define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_AIX(func)
# define INTERCEPT_FUNCTION_VER(func, symver) INTERCEPT_FUNCTION_AIX(func)
#elif SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || \
SANITIZER_SOLARIS || SANITIZER_HAIKU
# include "interception_linux.h"
# define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func)

View file

@ -0,0 +1,45 @@
//===-- interception_aix.cpp ------------------------------------*- 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
//
//===----------------------------------------------------------------------===//
//
// This file is a part of AddressSanitizer, an address sanity checker.
//
// AIX-specific interception methods.
//===----------------------------------------------------------------------===//
#include "interception.h"
#include "sanitizer_common/sanitizer_common.h"
#if SANITIZER_AIX
# include <dlfcn.h> // for dlsym()
namespace __interception {
static void *GetFuncAddr(const char *name, uptr wrapper_addr) {
// AIX dlsym can only defect the functions that are exported, so
// on AIX, we can not intercept some basic functions like memcpy.
// FIXME: if we are going to ship dynamic asan library, we may need to search
// all the loaded modules with RTLD_DEFAULT if RTLD_NEXT failed.
void *addr = dlsym(RTLD_NEXT, name);
// In case `name' is not loaded, dlsym ends up finding the actual wrapper.
// We don't want to intercept the wrapper and have it point to itself.
if ((uptr)addr == wrapper_addr)
addr = nullptr;
return addr;
}
bool InterceptFunction(const char *name, uptr *ptr_to_real, uptr func,
uptr wrapper) {
void *addr = GetFuncAddr(name, wrapper);
*ptr_to_real = (uptr)addr;
return addr && (func == wrapper);
}
} // namespace __interception
#endif // SANITIZER_AIX

View file

@ -0,0 +1,36 @@
//===-- interception_aix.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
//
//===----------------------------------------------------------------------===//
//
// This file is a part of AddressSanitizer, an address sanity checker.
//
// AIX-specific interception methods.
//===----------------------------------------------------------------------===//
#if SANITIZER_AIX
# if !defined(INCLUDED_FROM_INTERCEPTION_LIB)
# error \
"interception_aix.h should be included from interception library only"
# endif
# ifndef INTERCEPTION_AIX_H
# define INTERCEPTION_AIX_H
namespace __interception {
bool InterceptFunction(const char *name, uptr *ptr_to_real, uptr func,
uptr wrapper);
} // namespace __interception
# define INTERCEPT_FUNCTION_AIX(func) \
::__interception::InterceptFunction( \
#func, (::__interception::uptr *)&REAL(func), \
(::__interception::uptr) & (func), \
(::__interception::uptr) & WRAP(func))
# endif // INTERCEPTION_AIX_H
#endif // SANITIZER_AIX

View file

@ -14,7 +14,7 @@
#include "interception.h"
#if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || \
SANITIZER_SOLARIS
SANITIZER_SOLARIS || SANITIZER_HAIKU
#include <dlfcn.h> // for dlsym() and dlvsym()
@ -80,4 +80,4 @@ bool InterceptFunction(const char *name, const char *ver, uptr *ptr_to_real,
} // namespace __interception
#endif // SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD ||
// SANITIZER_SOLARIS
// SANITIZER_SOLARIS || SANITIZER_HAIKU

View file

@ -12,7 +12,7 @@
//===----------------------------------------------------------------------===//
#if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || \
SANITIZER_SOLARIS
SANITIZER_SOLARIS || SANITIZER_HAIKU
#if !defined(INCLUDED_FROM_INTERCEPTION_LIB)
# error interception_linux.h should be included from interception library only
@ -52,4 +52,4 @@ bool InterceptFunction(const char *name, const char *ver, uptr *ptr_to_real,
#endif // INTERCEPTION_LINUX_H
#endif // SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD ||
// SANITIZER_SOLARIS
// SANITIZER_SOLARIS || SANITIZER_HAIKU

View file

@ -646,6 +646,7 @@ static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) {
case 0xC033: // 33 C0 : xor eax, eax
case 0xC933: // 33 C9 : xor ecx, ecx
case 0xD233: // 33 D2 : xor edx, edx
case 0x9066: // 66 90 : xchg %ax,%ax (Two-byte NOP)
case 0xDB84: // 84 DB : test bl,bl
case 0xC084: // 84 C0 : test al,al
case 0xC984: // 84 C9 : test cl,cl
@ -726,7 +727,6 @@ static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) {
case 0x5541: // push r13
case 0x5641: // push r14
case 0x5741: // push r15
case 0x9066: // Two-byte NOP
case 0xc084: // test al, al
case 0x018a: // mov al, byte ptr [rcx]
return 2;
@ -743,6 +743,7 @@ static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) {
case 0x058B: // 8B 05 XX XX XX XX : mov eax, dword ptr [XX XX XX XX]
if (rel_offset)
*rel_offset = 2;
FALLTHROUGH;
case 0xB841: // 41 B8 XX XX XX XX : mov r8d, XX XX XX XX
return 6;
@ -753,6 +754,12 @@ static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) {
case 0x7B81: // 81 7B YY XX XX XX XX cmp DWORD PTR [rbx+YY], XX XX XX XX
case 0x7981: // 81 79 YY XX XX XX XX cmp dword ptr [rcx+YY], XX XX XX XX
return 7;
case 0xb848: // 48 b8 XX XX XX XX XX XX XX XX :
// movabsq XX XX XX XX XX XX XX XX, rax
case 0xba48: // 48 ba XX XX XX XX XX XX XX XX :
// movabsq XX XX XX XX XX XX XX XX, rdx
return 10;
}
switch (0x00FFFFFF & *(u32 *)address) {

View file

@ -23,7 +23,7 @@ namespace __sanitizer {
typedef CompactSizeClassMap InternalSizeClassMap;
struct AP32 {
static const uptr kSpaceBeg = 0;
static const uptr kSpaceBeg = SANITIZER_MMAP_BEGIN;
static const u64 kSpaceSize = SANITIZER_MMAP_RANGE_SIZE;
static const uptr kMetadataSize = 0;
typedef InternalSizeClassMap SizeClassMap;

View file

@ -166,7 +166,7 @@ struct SizeClassAllocator32LocalCache {
DCHECK_GT(c->count, 0);
}
void *res = c->batch[--c->count];
PREFETCH(c->batch[c->count - 1]);
PREFETCH(c->batch[c->count > 0 ? c->count - 1 : 0]);
stats_.Add(AllocatorStatAllocated, c->class_size);
return res;
}

View file

@ -14,6 +14,18 @@
#ifndef SANITIZER_ATOMIC_CLANG_H
#define SANITIZER_ATOMIC_CLANG_H
// Helper to suppress warnings related to 8-byte atomic accesses when the target
// is 32-bit AIX (where such accesses use libatomic).
#if defined(_AIX) && !defined(__powerpc64__) && defined(__clang__)
# define SANITIZER_IGNORE_ATOMIC_ALIGNMENT_BEGIN \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Watomic-alignment\"")
# define SANITIZER_IGNORE_ATOMIC_ALIGNMENT_END _Pragma("clang diagnostic pop")
#else
# define SANITIZER_IGNORE_ATOMIC_ALIGNMENT_BEGIN
# define SANITIZER_IGNORE_ATOMIC_ALIGNMENT_END
#endif
namespace __sanitizer {
// We use the compiler builtin atomic operations for loads and stores, which
@ -35,6 +47,7 @@ inline void proc_yield(int cnt) {
#endif
}
SANITIZER_IGNORE_ATOMIC_ALIGNMENT_BEGIN
template <typename T>
inline typename T::Type atomic_load(const volatile T *a, memory_order mo) {
DCHECK(mo == memory_order_relaxed || mo == memory_order_consume ||
@ -92,6 +105,8 @@ inline bool atomic_compare_exchange_weak(volatile T *a, typename T::Type *cmp,
return atomic_compare_exchange_strong(a, cmp, xchg, mo);
}
SANITIZER_IGNORE_ATOMIC_ALIGNMENT_END
} // namespace __sanitizer
#undef ATOMIC_ORDER

View file

@ -166,7 +166,7 @@ uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding,
// Used to check if we can map shadow memory to a fixed location.
bool MemoryRangeIsAvailable(uptr range_start, uptr range_end);
// Releases memory pages entirely within the [beg, end] address range. Noop if
// Releases memory pages entirely within the [beg, end) address range. Noop if
// the provided range does not contain at least one entire page.
void ReleaseMemoryPagesToOS(uptr beg, uptr end);
void IncreaseTotalMmap(uptr size);
@ -925,12 +925,6 @@ class ListOfModules {
// Callback type for iterating over a set of memory ranges.
typedef void (*RangeIteratorCallback)(uptr begin, uptr end, void *arg);
enum AndroidApiLevel {
ANDROID_NOT_ANDROID = 0,
ANDROID_LOLLIPOP_MR1 = 22,
ANDROID_POST_LOLLIPOP = 23
};
void WriteToSyslog(const char *buffer);
#if defined(SANITIZER_WINDOWS) && defined(_MSC_VER) && !defined(__clang__)
@ -963,19 +957,8 @@ inline void AndroidLogInit() {}
inline void SetAbortMessage(const char *) {}
#endif
#if SANITIZER_ANDROID
void SanitizerInitializeUnwinder();
AndroidApiLevel AndroidGetApiLevel();
#else
inline void AndroidLogWrite(const char *buffer_unused) {}
inline void SanitizerInitializeUnwinder() {}
inline AndroidApiLevel AndroidGetApiLevel() { return ANDROID_NOT_ANDROID; }
#endif
inline uptr GetPthreadDestructorIterations() {
#if SANITIZER_ANDROID
return (AndroidGetApiLevel() == ANDROID_LOLLIPOP_MR1) ? 8 : 4;
#elif SANITIZER_POSIX
#if SANITIZER_POSIX
return 4;
#else
// Unused on Windows.

View file

@ -481,7 +481,8 @@ INTERCEPTOR(char*, textdomain, const char *domainname) {
#endif
#if SANITIZER_INTERCEPT_STRCMP || SANITIZER_INTERCEPT_MEMCMP
static inline int CharCmpX(unsigned char c1, unsigned char c2) {
[[maybe_unused]] static inline int CharCmpX(unsigned char c1,
unsigned char c2) {
return (c1 == c2) ? 0 : (c1 < c2) ? -1 : 1;
}
#endif
@ -953,7 +954,7 @@ INTERCEPTOR(double, frexp, double x, int *exp) {
#define INIT_FREXP
#endif // SANITIZER_INTERCEPT_FREXP
#if SANITIZER_INTERCEPT_FREXPF_FREXPL
#if SANITIZER_INTERCEPT_FREXPF
INTERCEPTOR(float, frexpf, float x, int *exp) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, frexpf, x, exp);
@ -963,6 +964,12 @@ INTERCEPTOR(float, frexpf, float x, int *exp) {
return res;
}
# define INIT_FREXPF COMMON_INTERCEPT_FUNCTION(frexpf);
#else
# define INIT_FREXPF
#endif
#if SANITIZER_INTERCEPT_FREXPL
INTERCEPTOR(long double, frexpl, long double x, int *exp) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, frexpl, x, exp);
@ -972,12 +979,10 @@ INTERCEPTOR(long double, frexpl, long double x, int *exp) {
return res;
}
#define INIT_FREXPF_FREXPL \
COMMON_INTERCEPT_FUNCTION(frexpf); \
COMMON_INTERCEPT_FUNCTION_LDBL(frexpl)
# define INIT_FREXPL COMMON_INTERCEPT_FUNCTION_LDBL(frexpl)
#else
#define INIT_FREXPF_FREXPL
#endif // SANITIZER_INTERCEPT_FREXPF_FREXPL
# define INIT_FREXPL
#endif
#if SI_POSIX
static void write_iovec(void *ctx, struct __sanitizer_iovec *iovec,
@ -1346,7 +1351,8 @@ INTERCEPTOR(unsigned long, time, unsigned long *t) {
#if SANITIZER_INTERCEPT_LOCALTIME_AND_FRIENDS
static void unpoison_tm(void *ctx, __sanitizer_tm *tm) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tm, sizeof(*tm));
#if !SANITIZER_SOLARIS
// AIX tm struct does not have tm_zone field.
# if !SANITIZER_SOLARIS && !SANITIZER_AIX
if (tm->tm_zone) {
// Can not use COMMON_INTERCEPTOR_WRITE_RANGE here, because tm->tm_zone
// can point to shared memory and tsan would report a data race.
@ -1731,10 +1737,12 @@ INTERCEPTOR(int, __vsprintf_chk, char *str, int flag, SIZE_T size_to,
VSPRINTF_INTERCEPTOR_IMPL(vsprintf, str, format, ap)
#endif
# if SANITIZER_INTERCEPT_VASPRINTF
INTERCEPTOR(int, vasprintf, char **strp, const char *format, va_list ap)
VASPRINTF_INTERCEPTOR_IMPL(vasprintf, strp, format, ap)
# endif
#if SANITIZER_INTERCEPT_ISOC99_PRINTF
# if SANITIZER_INTERCEPT_ISOC99_PRINTF
INTERCEPTOR(int, __isoc99_vprintf, const char *format, va_list ap)
VPRINTF_INTERCEPTOR_IMPL(__isoc99_vprintf, format, ap)
@ -1783,10 +1791,12 @@ INTERCEPTOR(int, __snprintf_chk, char *str, SIZE_T size, int flag,
FORMAT_INTERCEPTOR_IMPL(__snprintf_chk, vsnprintf, str, size, format)
#endif
# if SANITIZER_INTERCEPT_ASPRINTF
INTERCEPTOR(int, asprintf, char **strp, const char *format, ...)
FORMAT_INTERCEPTOR_IMPL(asprintf, vasprintf, strp, format)
# endif
#if SANITIZER_INTERCEPT_ISOC99_PRINTF
# if SANITIZER_INTERCEPT_ISOC99_PRINTF
INTERCEPTOR(int, __isoc99_printf, const char *format, ...)
FORMAT_INTERCEPTOR_IMPL(__isoc99_printf, __isoc99_vprintf, format)
@ -1807,17 +1817,24 @@ FORMAT_INTERCEPTOR_IMPL(__isoc99_snprintf, __isoc99_vsnprintf, str, size,
#endif // SANITIZER_INTERCEPT_PRINTF
#if SANITIZER_INTERCEPT_PRINTF
#define INIT_PRINTF \
# define INIT_PRINTF_COMMON \
COMMON_INTERCEPT_FUNCTION_LDBL(printf); \
COMMON_INTERCEPT_FUNCTION_LDBL(sprintf); \
COMMON_INTERCEPT_FUNCTION_LDBL(snprintf); \
COMMON_INTERCEPT_FUNCTION_LDBL(asprintf); \
COMMON_INTERCEPT_FUNCTION_LDBL(fprintf); \
COMMON_INTERCEPT_FUNCTION_LDBL(vprintf); \
COMMON_INTERCEPT_FUNCTION_LDBL(vsprintf); \
COMMON_INTERCEPT_FUNCTION_LDBL(vsnprintf); \
COMMON_INTERCEPT_FUNCTION_LDBL(vasprintf); \
COMMON_INTERCEPT_FUNCTION_LDBL(vfprintf);
# if !SANITIZER_AIX
// AIX does not have [v]asprintf.
# define INIT_PRINTF_EXTRA \
COMMON_INTERCEPT_FUNCTION_LDBL(asprintf); \
COMMON_INTERCEPT_FUNCTION_LDBL(vasprintf);
# else
# define INIT_PRINTF_EXTRA
# endif
# define INIT_PRINTF INIT_PRINTF_COMMON INIT_PRINTF_EXTRA
#else
#define INIT_PRINTF
#endif
@ -1855,6 +1872,22 @@ FORMAT_INTERCEPTOR_IMPL(__isoc99_snprintf, __isoc99_vsnprintf, str, size,
#define INIT_ISOC99_PRINTF
#endif
#if SANITIZER_INTERCEPT_SETPROCTITLE
INTERCEPTOR(void, setproctitle, const char *fmt, ...) {
void *ctx;
va_list ap;
va_start(ap, fmt);
COMMON_INTERCEPTOR_ENTER(ctx, setproctitle, fmt, ap);
if (common_flags()->check_printf)
printf_common(ctx, fmt, ap);
REAL(setproctitle)(fmt, ap);
va_end(ap);
}
# define INIT_SETPROCTITLE COMMON_INTERCEPT_FUNCTION(setproctitle);
#else
# define INIT_SETPROCTITLE
#endif
#if SANITIZER_INTERCEPT_IOCTL
#include "sanitizer_common_interceptors_ioctl.inc"
#include "sanitizer_interceptors_ioctl_netbsd.inc"
@ -3901,7 +3934,7 @@ INTERCEPTOR(SIZE_T, wcrtomb, char *dest, wchar_t src, void *ps) {
if (res != ((SIZE_T)-1)) {
CHECK_LE(res, sizeof(local_dest));
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, res);
REAL(memcpy)(dest, local_dest, res);
internal_memcpy(dest, local_dest, res);
}
return res;
}
@ -3923,7 +3956,7 @@ INTERCEPTOR(int, wctomb, char *dest, wchar_t src) {
if (res != -1) {
CHECK_LE(res, sizeof(local_dest));
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, res);
REAL(memcpy)(dest, local_dest, res);
internal_memcpy(dest, local_dest, res);
}
return res;
}
@ -10263,6 +10296,71 @@ INTERCEPTOR(SSIZE_T, freadlink, int fd, char *buf, SIZE_T bufsiz) {
# define INIT_FREADLINK
#endif
#if SANITIZER_INTERCEPT_GETSERVENT_R || SANITIZER_INTERCEPT_GETSERVBYNAME_R || \
SANITIZER_INTERCEPT_GETSERVBYPORT_R
UNUSED static void HandleGetServentReentrantResult(
void *ctx, int res, struct __sanitizer_servent *result_buf, char *buf,
SIZE_T buflen, struct __sanitizer_servent **result) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, (char *)result, sizeof(void *));
if (res)
return;
if (*result) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, (char *)*result,
sizeof(__sanitizer_servent));
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, buflen);
}
}
#endif
#if SANITIZER_INTERCEPT_GETSERVENT_R
INTERCEPTOR(int, getservent_r, struct __sanitizer_servent *result_buf,
char *buf, SIZE_T buflen, struct __sanitizer_servent **result) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, getservent_r, result_buf, buf, buflen, result);
int res = REAL(getservent_r)(result_buf, buf, buflen, result);
HandleGetServentReentrantResult(ctx, res, result_buf, buf, buflen, result);
return res;
}
# define INIT_GETSERVENT_R COMMON_INTERCEPT_FUNCTION(getservent_r)
#else
# define INIT_GETSERVENT_R
#endif
#if SANITIZER_INTERCEPT_GETSERVBYNAME_R
INTERCEPTOR(int, getservbyname_r, const char *name, const char *proto,
struct __sanitizer_servent *result_buf, char *buf, SIZE_T buflen,
struct __sanitizer_servent **result) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, getservbyname_r, name, proto, result_buf, buf,
buflen, result);
COMMON_INTERCEPTOR_READ_STRING(ctx, name, internal_strlen(name));
int res = REAL(getservbyname_r)(name, proto, result_buf, buf, buflen, result);
HandleGetServentReentrantResult(ctx, res, result_buf, buf, buflen, result);
return res;
}
# define INIT_GETSERVBYNAME_R COMMON_INTERCEPT_FUNCTION(getservbyname_r)
#else
# define INIT_GETSERVBYNAME_R
#endif
#if SANITIZER_INTERCEPT_GETSERVBYPORT_R
INTERCEPTOR(int, getservbyport_r, int port, const char *proto,
struct __sanitizer_servent *result_buf, char *buf, SIZE_T buflen,
struct __sanitizer_servent **result) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, getservbyport_r, port, proto, result_buf, buf,
buflen, result);
int res = REAL(getservbyport_r)(port, proto, result_buf, buf, buflen, result);
HandleGetServentReentrantResult(ctx, res, result_buf, buf, buflen, result);
return res;
}
# define INIT_GETSERVBYPORT_R COMMON_INTERCEPT_FUNCTION(getservbyport_r)
#else
# define INIT_GETSERVBYPORT_R
#endif
#include "sanitizer_common_interceptors_netbsd_compat.inc"
namespace __sanitizer {
@ -10328,8 +10426,10 @@ static void InitializeCommonInterceptors() {
INIT_PRINTF;
INIT_PRINTF_L;
INIT_ISOC99_PRINTF;
INIT_SETPROCTITLE;
INIT_FREXP;
INIT_FREXPF_FREXPL;
INIT_FREXPF;
INIT_FREXPL;
INIT_GETPWNAM_AND_FRIENDS;
INIT_GETPWNAM_R_AND_FRIENDS;
INIT_GETPWENT;
@ -10587,4 +10687,7 @@ static void InitializeCommonInterceptors() {
INIT_FREADLINK;
INIT___PRINTF_CHK;
INIT_GETSERVENT_R;
INIT_GETSERVBYNAME_R;
INIT_GETSERVBYPORT_R;
}

View file

@ -67,6 +67,10 @@ static const char *maybe_parse_length_modifier(const char *p, char ll[2]) {
// Returns true if the character is an integer conversion specifier.
static bool format_is_integer_conv(char c) {
#if SANITIZER_GLIBC
if (char_is_one_of(c, "bB"))
return true;
#endif
return char_is_one_of(c, "diouxXn");
}

View file

@ -48,35 +48,41 @@ static void ioctl_table_fill() {
++ioctl_table_size; \
}
_(FIONBIO, READ, sizeof(int));
#if !SANITIZER_HAIKU
_(FIOASYNC, READ, sizeof(int));
_(FIOCLEX, NONE, 0);
_(FIOGETOWN, WRITE, sizeof(int));
_(FIONBIO, READ, sizeof(int));
_(FIONCLEX, NONE, 0);
_(FIOSETOWN, READ, sizeof(int));
#endif
_(SIOCATMARK, WRITE, sizeof(int));
_(SIOCGIFCONF, CUSTOM, 0);
_(SIOCGPGRP, WRITE, sizeof(int));
_(SIOCSPGRP, READ, sizeof(int));
#if !SANITIZER_SOLARIS
#if !SANITIZER_SOLARIS && !SANITIZER_HAIKU
_(TIOCCONS, NONE, 0);
#endif
_(TIOCEXCL, NONE, 0);
#if !SANITIZER_HAIKU
_(TIOCGETD, WRITE, sizeof(int));
_(TIOCNOTTY, NONE, 0);
_(TIOCPKT, READ, sizeof(int));
_(TIOCSETD, READ, sizeof(int));
_(TIOCSTI, READ, sizeof(char));
#endif
_(TIOCEXCL, NONE, 0);
_(TIOCGPGRP, WRITE, pid_t_sz);
_(TIOCGWINSZ, WRITE, struct_winsize_sz);
_(TIOCMBIC, READ, sizeof(int));
_(TIOCMBIS, READ, sizeof(int));
_(TIOCMGET, WRITE, sizeof(int));
_(TIOCMSET, READ, sizeof(int));
_(TIOCNOTTY, NONE, 0);
_(TIOCNXCL, NONE, 0);
_(TIOCOUTQ, WRITE, sizeof(int));
_(TIOCPKT, READ, sizeof(int));
# if !SANITIZER_AIX
_(TIOCSCTTY, NONE, 0);
_(TIOCSETD, READ, sizeof(int));
# endif
_(TIOCSPGRP, READ, pid_t_sz);
_(TIOCSTI, READ, sizeof(char));
_(TIOCSWINSZ, READ, struct_winsize_sz);
#if !SANITIZER_IOS

View file

@ -33,11 +33,13 @@
// Platform-specific options.
#if SANITIZER_APPLE
#define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE 0
# define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE 0
#elif SANITIZER_WINDOWS64
#define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE 0
# define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE 0
#elif SANITIZER_AIX
# define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE 0
#else
#define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE 1
# define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE 1
#endif // SANITIZER_APPLE
#ifndef COMMON_INTERCEPTOR_MEMSET_IMPL

View file

@ -3205,6 +3205,28 @@ POST_SYSCALL(futex)
COMMON_SYSCALL_BLOCKING_END();
}
PRE_SYSCALL(copy_file_range)
(int fdin, __sanitizer___kernel_off_t *offin, int fdout,
__sanitizer___kernel_off_t *offout, SIZE_T size, unsigned int flags) {
if (offin != nullptr) {
PRE_READ(offin, sizeof(*offin));
}
if (offout != nullptr) {
PRE_READ(offout, sizeof(*offout));
}
}
POST_SYSCALL(copy_file_range)
(SSIZE_T, int fdin, __sanitizer___kernel_off_t *offin, int fdout,
__sanitizer___kernel_off_t *offout, SIZE_T size, unsigned int flags) {
if (offin != nullptr) {
POST_WRITE(offin, sizeof(*offin));
}
if (offout != nullptr) {
POST_WRITE(offout, sizeof(*offout));
}
}
} // extern "C"
# undef PRE_SYSCALL

View file

@ -29,6 +29,8 @@
# define __errno_location ___errno
#elif SANITIZER_WINDOWS
# define __errno_location _errno
#elif SANITIZER_HAIKU
# define __errno_location _errnop
#endif
extern "C" int *__errno_location();

View file

@ -21,12 +21,21 @@
namespace __sanitizer {
#define errno_ENOMEM 12
#define errno_EBUSY 16
#define errno_EINVAL 22
#define errno_ERANGE 34
#define errno_ENAMETOOLONG 36
#define errno_ENOSYS 38
#ifdef __HAIKU__
# define errno_ENOMEM (0x80000000)
# define errno_EBUSY (0x80000000 + 14)
# define errno_EINVAL (0x80000000 + 5)
# define errno_ERANGE (0x80007000 + 17)
# define errno_ENAMETOOLONG (0x80000000 + 0x6004)
# define errno_ENOSYS (0x80007009)
#else
# define errno_ENOMEM 12
# define errno_EBUSY 16
# define errno_EINVAL 22
# define errno_ERANGE 34
# define errno_ENAMETOOLONG 36
# define errno_ENOSYS 38
#endif
// Those might not present or their value differ on different platforms.
extern const int errno_EOWNERDEAD;

View file

@ -96,12 +96,76 @@ static void RecursiveCreateParentDirs(char *path) {
}
}
/// Parse the report path \p pattern and copy the parsed path to \p dest.
///
/// * `%%` becomes `%`
/// * `%H` expands to the environment variable `HOME`
/// * `%t` expands to the environment variable `TMPDIR`
/// * `%p` expands to the process ID (PID)
static void ParseAndSetPath(const char *pattern, char *dest,
const uptr dest_size) {
CHECK(pattern);
CHECK(dest);
CHECK_GE(dest_size, 1);
dest[0] = '\0';
uptr next_substr_start_idx = 0;
for (uptr i = 0; i < internal_strlen(pattern) - 1; i++) {
if (pattern[i] != '%')
continue;
int bytes_to_copy = i - next_substr_start_idx;
// Copy over previous substring.
CHECK_LT(internal_strlcat(dest, pattern + next_substr_start_idx,
internal_strlen(dest) + bytes_to_copy + 1),
dest_size);
const char *str_to_concat;
switch (pattern[++i]) {
case '%':
str_to_concat = "%";
break;
case 'H':
str_to_concat = GetEnv("HOME");
break;
case 't':
str_to_concat = GetEnv("TMPDIR");
break;
case 'p': {
// Use printf directly to write the PID since it's not a static string.
int remaining_capacity = dest_size - internal_strlen(dest);
int bytes_copied =
internal_snprintf(dest + internal_strlen(dest), remaining_capacity,
"%ld", internal_getpid());
CHECK_GT(bytes_copied, 0);
CHECK_LT(bytes_copied, remaining_capacity);
str_to_concat = "";
break;
}
default: {
// Invalid pattern: fallback to original pattern.
const char *message = "ERROR: Unexpected pattern: ";
WriteToFile(kStderrFd, message, internal_strlen(message));
WriteToFile(kStderrFd, pattern, internal_strlen(pattern));
WriteToFile(kStderrFd, "\n", internal_strlen("\n"));
CHECK_LT(internal_strlcpy(dest, pattern, dest_size), dest_size);
return;
}
}
CHECK(str_to_concat);
CHECK_LT(internal_strlcat(dest, str_to_concat, dest_size), dest_size);
next_substr_start_idx = i + 1;
}
CHECK_LT(internal_strlcat(dest, pattern + next_substr_start_idx, dest_size),
dest_size);
}
void ReportFile::SetReportPath(const char *path) {
if (path) {
uptr len = internal_strlen(path);
if (len > sizeof(path_prefix) - 100) {
Report("ERROR: Path is too long: %c%c%c%c%c%c%c%c...\n", path[0], path[1],
path[2], path[3], path[4], path[5], path[6], path[7]);
const char *message = "ERROR: Path is too long: ";
WriteToFile(kStderrFd, message, internal_strlen(message));
WriteToFile(kStderrFd, path, 8);
message = "...\n";
WriteToFile(kStderrFd, message, internal_strlen(message));
Die();
}
}
@ -115,7 +179,7 @@ void ReportFile::SetReportPath(const char *path) {
} else if (internal_strcmp(path, "stdout") == 0) {
fd = kStdoutFd;
} else {
internal_snprintf(path_prefix, kMaxPathLength, "%s", path);
ParseAndSetPath(path, path_prefix, kMaxPathLength);
RecursiveCreateParentDirs(path_prefix);
}
}

View file

@ -547,6 +547,8 @@ void __sanitizer_startup_hook(int argc, char **argv, char **envp,
__sanitizer::StoredEnviron = envp;
__sanitizer::MainThreadStackBase = reinterpret_cast<uintptr_t>(stack_base);
__sanitizer::MainThreadStackSize = stack_size;
EarlySanitizerInit();
}
void __sanitizer_set_report_path(const char *path) {

View file

@ -32,6 +32,13 @@ struct MemoryMappingLayoutData {
void InitShadowBounds();
// Individual sanitizers can define this to explicitly run something at the end
// of `__sanitizer_startup_hook`. This can be useful if a sanitizer needs to do
// extra work after the common startup hook code is called and before module
// ctors are invoked. For example, hwasan can explicitly call its initializing
// function here so it can be set up before libc extensions are initialized.
void EarlySanitizerInit();
} // namespace __sanitizer
#endif // SANITIZER_FUCHSIA

View file

@ -0,0 +1,361 @@
//===-- sanitizer_haiku.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 shared between Sanitizer run-time libraries and implements
// Haiku-specific functions from sanitizer_libc.h.
//===----------------------------------------------------------------------===//
#include "sanitizer_platform.h"
#if SANITIZER_HAIKU
# include "sanitizer_common.h"
# include "sanitizer_flags.h"
# include "sanitizer_getauxval.h"
# include "sanitizer_internal_defs.h"
# include "sanitizer_libc.h"
# include "sanitizer_linux.h"
# include "sanitizer_mutex.h"
# include "sanitizer_placement_new.h"
# include "sanitizer_procmaps.h"
# include <sys/param.h>
# include <sys/types.h>
# include <sys/mman.h>
# include <sys/resource.h>
# include <sys/stat.h>
# include <sys/time.h>
# include <dlfcn.h>
# include <errno.h>
# include <fcntl.h>
# include <limits.h>
# include <link.h>
# include <pthread.h>
# include <sched.h>
# include <signal.h>
# include <unistd.h>
# include "system/vm_defs.h"
# include "system/syscalls.h"
# include "shared/syscall_utils.h"
namespace __sanitizer {
static void *GetRealLibcAddress(const char *symbol) {
void *real = dlsym(RTLD_NEXT, symbol);
if (!real)
real = dlsym(RTLD_DEFAULT, symbol);
if (!real) {
Printf("GetRealLibcAddress failed for symbol=%s", symbol);
Die();
}
return real;
}
# define _REAL(func, ...) real##_##func(__VA_ARGS__)
# define DEFINE__REAL(ret_type, func, ...) \
static ret_type (*real_##func)(__VA_ARGS__) = NULL; \
if (!real_##func) { \
real_##func = (ret_type(*)(__VA_ARGS__))GetRealLibcAddress(#func); \
} \
CHECK(real_##func);
// --------------- sanitizer_libc.h
uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd,
u64 offset) {
if ((flags & MAP_ANONYMOUS) != 0)
fd = -1;
int mapping =
(flags & MAP_SHARED) != 0 ? REGION_NO_PRIVATE_MAP : REGION_PRIVATE_MAP;
uint32 addressSpec;
if ((flags & MAP_FIXED) != 0)
addressSpec = B_EXACT_ADDRESS;
else if (addr != NULL)
addressSpec = B_BASE_ADDRESS;
else
addressSpec = B_RANDOMIZED_ANY_ADDRESS;
uint32 areaProtection = 0;
if ((prot & PROT_READ) != 0)
areaProtection |= B_READ_AREA;
if ((prot & PROT_WRITE) != 0)
areaProtection |= B_WRITE_AREA;
if ((prot & PROT_EXEC) != 0)
areaProtection |= B_EXECUTE_AREA;
if ((flags & MAP_NORESERVE) != 0)
areaProtection |= B_OVERCOMMITTING_AREA;
area_id area = _kern_map_file("sanitizer mmap", &addr, addressSpec, length,
areaProtection, mapping, true, fd, offset);
if (area < 0)
RETURN_AND_SET_ERRNO(area);
return (uptr)addr;
}
uptr internal_munmap(void *addr, uptr length) {
DEFINE__REAL(int, munmap, void *a, uptr b);
return _REAL(munmap, addr, length);
}
uptr internal_mremap(void *old_address, uptr old_size, uptr new_size, int flags,
void *new_address) {
CHECK(false && "internal_mremap is unimplemented on Haiku");
return 0;
}
int internal_mprotect(void *addr, uptr length, int prot) {
DEFINE__REAL(int, mprotect, void *a, uptr b, int c);
return _REAL(mprotect, addr, length, prot);
}
int internal_madvise(uptr addr, uptr length, int advice) {
DEFINE__REAL(int, madvise, void *a, uptr b, int c);
return _REAL(madvise, (void *)addr, length, advice);
}
uptr internal_close(fd_t fd) {
CHECK(&_kern_close);
RETURN_AND_SET_ERRNO(_kern_close(fd));
}
uptr internal_open(const char *filename, int flags) {
CHECK(&_kern_open);
RETURN_AND_SET_ERRNO(_kern_open(-1, filename, flags, 0));
}
uptr internal_open(const char *filename, int flags, u32 mode) {
CHECK(&_kern_open);
RETURN_AND_SET_ERRNO(_kern_open(-1, filename, flags, mode));
}
uptr internal_read(fd_t fd, void *buf, uptr count) {
sptr res;
CHECK(&_kern_read);
HANDLE_EINTR(res, (sptr)_kern_read(fd, -1, buf, (size_t)count));
RETURN_AND_SET_ERRNO(res);
return res;
}
uptr internal_write(fd_t fd, const void *buf, uptr count) {
sptr res;
CHECK(&_kern_write);
HANDLE_EINTR(res, (sptr)_kern_write(fd, -1, buf, count));
RETURN_AND_SET_ERRNO(res);
return res;
}
uptr internal_ftruncate(fd_t fd, uptr size) {
sptr res;
DEFINE__REAL(int, ftruncate, int, off_t);
return _REAL(ftruncate, fd, size);
return res;
}
uptr internal_stat(const char *path, void *buf) {
DEFINE__REAL(int, _stat_current, const char *a, void *b);
return _REAL(_stat_current, path, buf);
}
uptr internal_lstat(const char *path, void *buf) {
DEFINE__REAL(int, _lstat_current, const char *a, void *b);
return _REAL(_lstat_current, path, buf);
}
uptr internal_fstat(fd_t fd, void *buf) {
DEFINE__REAL(int, _fstat_current, int a, void *b);
return _REAL(_fstat_current, fd, buf);
}
uptr internal_filesize(fd_t fd) {
struct stat st;
if (internal_fstat(fd, &st))
return -1;
return (uptr)st.st_size;
}
uptr internal_dup(int oldfd) {
DEFINE__REAL(int, dup, int a);
return _REAL(dup, oldfd);
}
uptr internal_dup2(int oldfd, int newfd) {
DEFINE__REAL(int, dup2, int a, int b);
return _REAL(dup2, oldfd, newfd);
}
uptr internal_readlink(const char *path, char *buf, uptr bufsize) {
CHECK(&_kern_read_link);
RETURN_AND_SET_ERRNO(_kern_read_link(-1, path, buf, &bufsize));
}
uptr internal_unlink(const char *path) {
DEFINE__REAL(int, unlink, const char *a);
return _REAL(unlink, path);
}
uptr internal_rename(const char *oldpath, const char *newpath) {
DEFINE__REAL(int, rename, const char *a, const char *b);
return _REAL(rename, oldpath, newpath);
}
uptr internal_sched_yield() {
CHECK(&_kern_thread_yield);
_kern_thread_yield();
return 0;
}
void internal__exit(int exitcode) {
DEFINE__REAL(void, _exit, int a);
_REAL(_exit, exitcode);
Die(); // Unreachable.
}
void internal_usleep(u64 useconds) {
_kern_snooze_etc(useconds, B_SYSTEM_TIMEBASE, B_RELATIVE_TIMEOUT, NULL);
}
uptr internal_execve(const char *filename, char *const argv[],
char *const envp[]) {
DEFINE__REAL(int, execve, const char *, char *const[], char *const[]);
return _REAL(execve, filename, argv, envp);
}
# if 0
tid_t GetTid() {
DEFINE__REAL(int, _lwp_self);
return _REAL(_lwp_self);
}
int TgKill(pid_t pid, tid_t tid, int sig) {
DEFINE__REAL(int, _lwp_kill, int a, int b);
(void)pid;
return _REAL(_lwp_kill, tid, sig);
}
u64 NanoTime() {
timeval tv;
DEFINE__REAL(int, __gettimeofday50, void *a, void *b);
internal_memset(&tv, 0, sizeof(tv));
_REAL(__gettimeofday50, &tv, 0);
return (u64)tv.tv_sec * 1000 * 1000 * 1000 + tv.tv_usec * 1000;
}
# endif
uptr internal_clock_gettime(__sanitizer_clockid_t clk_id, void *tp) {
DEFINE__REAL(int, __clock_gettime50, __sanitizer_clockid_t a, void *b);
return _REAL(__clock_gettime50, clk_id, tp);
}
uptr internal_ptrace(int request, int pid, void *addr, int data) {
DEFINE__REAL(int, ptrace, int a, int b, void *c, int d);
return _REAL(ptrace, request, pid, addr, data);
}
uptr internal_waitpid(int pid, int *status, int options) {
DEFINE__REAL(int, waitpid, pid_t, int *, int);
return _REAL(waitpid, pid, status, options);
}
uptr internal_getpid() {
DEFINE__REAL(int, getpid);
return _REAL(getpid);
}
uptr internal_getppid() {
DEFINE__REAL(int, 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);
}
uptr internal_lseek(fd_t fd, OFF_T offset, int whence) {
CHECK(&_kern_seek);
off_t result = _kern_seek(fd, offset, whence);
if (result < 0) {
errno = result;
return -1;
}
return result;
}
uptr internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5) {
Printf("internal_prctl not implemented for Haiku");
Die();
return 0;
}
uptr internal_sigaltstack(const void *ss, void *oss) {
DEFINE__REAL(int, __sigaltstack14, const void *a, void *b);
return _REAL(__sigaltstack14, ss, oss);
}
int internal_fork() {
DEFINE__REAL(int, fork);
return _REAL(fork);
}
# if 0
int internal_sysctl(const int *name, unsigned int namelen, void *oldp,
uptr *oldlenp, const void *newp, uptr newlen) {
CHECK(&__sysctl);
return __sysctl(name, namelen, oldp, (size_t *)oldlenp, newp, (size_t)newlen);
}
# endif
int internal_sysctlbyname(const char *sname, void *oldp, uptr *oldlenp,
const void *newp, uptr newlen) {
DEFINE__REAL(int, sysctlbyname, const char *a, void *b, size_t *c,
const void *d, size_t e);
return _REAL(sysctlbyname, sname, oldp, (size_t *)oldlenp, newp,
(size_t)newlen);
}
uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set,
__sanitizer_sigset_t *oldset) {
CHECK(&_kern_set_signal_mask);
return _kern_set_signal_mask(how, set, oldset);
}
void internal_sigfillset(__sanitizer_sigset_t *set) {
DEFINE__REAL(int, __sigfillset14, const void *a);
(void)_REAL(__sigfillset14, set);
}
void internal_sigemptyset(__sanitizer_sigset_t *set) {
DEFINE__REAL(int, __sigemptyset14, const void *a);
(void)_REAL(__sigemptyset14, set);
}
void internal_sigdelset(__sanitizer_sigset_t *set, int signo) {
DEFINE__REAL(int, __sigdelset14, const void *a, int b);
(void)_REAL(__sigdelset14, set, signo);
}
uptr internal_clone(int (*fn)(void *), void *child_stack, int flags,
void *arg) {
DEFINE__REAL(int, clone, int (*a)(void *b), void *c, int d, void *e);
return _REAL(clone, fn, child_stack, flags, arg);
}
} // namespace __sanitizer
#endif

View file

@ -14,7 +14,7 @@
#include "sanitizer_platform.h"
#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \
SANITIZER_SOLARIS
SANITIZER_SOLARIS || SANITIZER_HAIKU
# include "sanitizer_common.h"
# include "sanitizer_flags.h"
@ -63,15 +63,17 @@
# include <sched.h>
# include <signal.h>
# include <sys/mman.h>
# if !SANITIZER_SOLARIS
# if !SANITIZER_SOLARIS && !SANITIZER_HAIKU
# include <sys/ptrace.h>
# endif
# include <sys/resource.h>
# include <sys/stat.h>
# if !SANITIZER_HAIKU
# include <sys/syscall.h>
# include <ucontext.h>
# endif
# include <sys/time.h>
# include <sys/types.h>
# include <ucontext.h>
# include <unistd.h>
# if SANITIZER_LINUX
@ -82,6 +84,12 @@
# include <sys/personality.h>
# endif
# if SANITIZER_ANDROID && __ANDROID_API__ < 35
// The weak `strerrorname_np` (introduced in API level 35) definition,
// allows for checking the API level at runtime.
extern "C" SANITIZER_WEAK_ATTRIBUTE const char *strerrorname_np(int);
# endif
# if SANITIZER_LINUX && defined(__loongarch__)
# include <sys/sysmacros.h>
# endif
@ -118,6 +126,13 @@ extern struct ps_strings *__ps_strings;
# define environ _environ
# endif
# if SANITIZER_HAIKU
# include <OS.h>
# include <elf.h>
# include <image.h>
extern "C" char **__libc_argv;
# endif
extern char **environ;
# if SANITIZER_LINUX
@ -246,7 +261,7 @@ ScopedBlockSignals::~ScopedBlockSignals() { SetSigProcMask(&saved_, nullptr); }
# endif
// --------------- sanitizer_libc.h
# if !SANITIZER_SOLARIS && !SANITIZER_NETBSD
# if !SANITIZER_SOLARIS && !SANITIZER_NETBSD && !SANITIZER_HAIKU
# if !SANITIZER_S390
uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd,
u64 offset) {
@ -591,9 +606,9 @@ uptr internal_execve(const char *filename, char *const argv[],
return internal_syscall(SYSCALL(execve), (uptr)filename, (uptr)argv,
(uptr)envp);
}
# endif // !SANITIZER_SOLARIS && !SANITIZER_NETBSD
# endif // !SANITIZER_SOLARIS && !SANITIZER_NETBSD && !SANITIZER_HAIKU
# if !SANITIZER_NETBSD
# if !SANITIZER_NETBSD && !SANITIZER_HAIKU
void internal__exit(int exitcode) {
# if SANITIZER_FREEBSD || SANITIZER_SOLARIS
internal_syscall(SYSCALL(exit), exitcode);
@ -602,7 +617,7 @@ void internal__exit(int exitcode) {
# endif
Die(); // Unreachable.
}
# endif // !SANITIZER_NETBSD
# endif // !SANITIZER_NETBSD && !SANITIZER_HAIKU
// ----------------- sanitizer_common.h
bool FileExists(const char *filename) {
@ -630,6 +645,8 @@ tid_t GetTid() {
return Tid;
# elif SANITIZER_SOLARIS
return thr_self();
# elif SANITIZER_HAIKU
return find_thread(NULL);
# else
return internal_syscall(SYSCALL(gettid));
# endif
@ -645,6 +662,8 @@ int TgKill(pid_t pid, tid_t tid, int sig) {
errno = thr_kill(tid, sig);
// TgKill is expected to return -1 on error, not an errno.
return errno != 0 ? -1 : 0;
# elif SANITIZER_HAIKU
return kill_thread(tid);
# endif
}
# endif
@ -672,7 +691,8 @@ u64 NanoTime() {
// 'environ' array (on some others) and does not use libc. This function
// should be called first inside __asan_init.
const char *GetEnv(const char *name) {
# if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_SOLARIS
# if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_SOLARIS || \
SANITIZER_HAIKU
if (::environ != 0) {
uptr NameLen = internal_strlen(name);
for (char **Env = ::environ; *Env != 0; Env++) {
@ -710,13 +730,14 @@ const char *GetEnv(const char *name) {
# endif
}
# if !SANITIZER_FREEBSD && !SANITIZER_NETBSD && !SANITIZER_GO
# if !SANITIZER_HAIKU && !SANITIZER_FREEBSD && !SANITIZER_NETBSD && \
!SANITIZER_GO
extern "C" {
SANITIZER_WEAK_ATTRIBUTE extern void *__libc_stack_end;
}
# endif
# if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
# if !SANITIZER_HAIKU && !SANITIZER_FREEBSD && !SANITIZER_NETBSD
static void ReadNullSepFileToArray(const char *path, char ***arr,
int arr_size) {
char *buff;
@ -743,7 +764,10 @@ static void ReadNullSepFileToArray(const char *path, char ***arr,
# endif
static void GetArgsAndEnv(char ***argv, char ***envp) {
# if SANITIZER_FREEBSD
# if SANITIZER_HAIKU
*argv = __libc_argv;
*envp = environ;
# elif SANITIZER_FREEBSD
// On FreeBSD, retrieving the argument and environment arrays is done via the
// kern.ps_strings sysctl, which returns a pointer to a structure containing
// this information. See also <sys/exec.h>.
@ -783,7 +807,7 @@ static void GetArgsAndEnv(char ***argv, char ***envp) {
# if !SANITIZER_GO
}
# endif // !SANITIZER_GO
# endif // SANITIZER_FREEBSD
# endif // SANITIZER_HAIKU
}
char **GetArgv() {
@ -802,7 +826,7 @@ char **GetEnviron() {
void FutexWait(atomic_uint32_t *p, u32 cmp) {
# if SANITIZER_FREEBSD
_umtx_op(p, UMTX_OP_WAIT_UINT, cmp, 0, 0);
# elif SANITIZER_NETBSD
# elif SANITIZER_NETBSD || SANITIZER_HAIKU
sched_yield(); /* No userspace futex-like synchronization */
# else
internal_syscall(SYSCALL(futex), (uptr)p, FUTEX_WAIT_PRIVATE, cmp, 0, 0, 0);
@ -812,7 +836,7 @@ void FutexWait(atomic_uint32_t *p, u32 cmp) {
void FutexWake(atomic_uint32_t *p, u32 count) {
# if SANITIZER_FREEBSD
_umtx_op(p, UMTX_OP_WAKE, count, 0, 0);
# elif SANITIZER_NETBSD
# elif SANITIZER_NETBSD || SANITIZER_HAIKU
/* No userspace futex-like synchronization */
# else
internal_syscall(SYSCALL(futex), (uptr)p, FUTEX_WAKE_PRIVATE, count, 0, 0, 0);
@ -844,7 +868,7 @@ struct linux_dirent {
};
# endif
# if !SANITIZER_SOLARIS && !SANITIZER_NETBSD
# if !SANITIZER_SOLARIS && !SANITIZER_NETBSD && !SANITIZER_HAIKU
// Syscall wrappers.
uptr internal_ptrace(int request, int pid, void *addr, void *data) {
return internal_syscall(SYSCALL(ptrace), request, pid, (uptr)addr,
@ -1058,7 +1082,7 @@ bool internal_sigismember(__sanitizer_sigset_t *set, int signum) {
# endif
# endif // !SANITIZER_SOLARIS
# if !SANITIZER_NETBSD
# if !SANITIZER_NETBSD && !SANITIZER_HAIKU
// ThreadLister implementation.
ThreadLister::ThreadLister(pid_t pid) : buffer_(4096) {
task_path_.AppendF("/proc/%d/task", pid);
@ -1244,6 +1268,16 @@ uptr GetPageSize() {
CHECK_EQ(rv, 0);
return (uptr)pz;
# elif SANITIZER_USE_GETAUXVAL
# if SANITIZER_ANDROID && __ANDROID_API__ < 35
// The 16 KB page size was introduced in Android 15 (API level 35), while
// earlier versions of Android always used a 4 KB page size.
// We are checking the weak definition of `strerrorname_np` (introduced in API
// level 35) because some earlier API levels crashed when
// `getauxval(AT_PAGESZ)` was called from the `.preinit_array`.
if (!strerrorname_np)
return 4096;
# endif
return getauxval(AT_PAGESZ);
# else
return sysconf(_SC_PAGESIZE); // EXEC_PAGESIZE may not be trustworthy.
@ -1252,7 +1286,19 @@ uptr GetPageSize() {
# endif
uptr ReadBinaryName(/*out*/ char *buf, uptr buf_len) {
# if SANITIZER_SOLARIS
# if SANITIZER_HAIKU
int cookie = 0;
image_info info;
const char *argv0 = "<UNKNOWN>";
while (get_next_image_info(B_CURRENT_TEAM, &cookie, &info) == B_OK) {
if (info.type != B_APP_IMAGE)
continue;
argv0 = info.name;
break;
}
internal_strncpy(buf, argv0, buf_len);
return internal_strlen(buf);
# elif SANITIZER_SOLARIS
const char *default_module_name = getexecname();
CHECK_NE(default_module_name, NULL);
return internal_snprintf(buf, buf_len, "%s", default_module_name);
@ -1318,11 +1364,11 @@ bool LibraryNameIs(const char *full_name, const char *base_name) {
return (name[base_name_length] == '-' || name[base_name_length] == '.');
}
# if !SANITIZER_ANDROID
# if !SANITIZER_ANDROID && !SANITIZER_HAIKU
// Call cb for each region mapped by map.
void ForEachMappedRegion(link_map *map, void (*cb)(const void *, uptr)) {
CHECK_NE(map, nullptr);
# if !SANITIZER_FREEBSD
# if !SANITIZER_FREEBSD && !SANITIZER_HAIKU
typedef ElfW(Phdr) Elf_Phdr;
typedef ElfW(Ehdr) Elf_Ehdr;
# endif // !SANITIZER_FREEBSD
@ -1855,54 +1901,6 @@ int internal_uname(struct utsname *buf) {
}
# endif
# if SANITIZER_ANDROID
static int dl_iterate_phdr_test_cb(struct dl_phdr_info *info, size_t size,
void *data) {
// Any name starting with "lib" indicates a bug in L where library base names
// are returned instead of paths.
if (info->dlpi_name && info->dlpi_name[0] == 'l' &&
info->dlpi_name[1] == 'i' && info->dlpi_name[2] == 'b') {
*(bool *)data = true;
return 1;
}
return 0;
}
static atomic_uint32_t android_api_level;
static AndroidApiLevel AndroidDetectApiLevelStatic() {
# if __ANDROID_API__ <= 22
return ANDROID_LOLLIPOP_MR1;
# else
return ANDROID_POST_LOLLIPOP;
# endif
}
static AndroidApiLevel AndroidDetectApiLevel() {
bool base_name_seen = false;
dl_iterate_phdr(dl_iterate_phdr_test_cb, &base_name_seen);
if (base_name_seen)
return ANDROID_LOLLIPOP_MR1; // L MR1
return ANDROID_POST_LOLLIPOP; // post-L
// Plain L (API level 21) is completely broken wrt ASan and not very
// interesting to detect.
}
extern "C" __attribute__((weak)) void *_DYNAMIC;
AndroidApiLevel AndroidGetApiLevel() {
AndroidApiLevel level =
(AndroidApiLevel)atomic_load(&android_api_level, memory_order_relaxed);
if (level)
return level;
level = &_DYNAMIC == nullptr ? AndroidDetectApiLevelStatic()
: AndroidDetectApiLevel();
atomic_store(&android_api_level, level, memory_order_relaxed);
return level;
}
# endif
static HandleSignalMode GetHandleSignalModeImpl(int signum) {
switch (signum) {
case SIGABRT:
@ -1981,11 +1979,15 @@ using Context = ucontext_t;
SignalContext::WriteFlag SignalContext::GetWriteFlag() const {
Context *ucontext = (Context *)context;
# if defined(__x86_64__) || defined(__i386__)
# if !SANITIZER_HAIKU
static const uptr PF_WRITE = 1U << 1;
# endif
# if SANITIZER_FREEBSD
uptr err = ucontext->uc_mcontext.mc_err;
# elif SANITIZER_NETBSD
uptr err = ucontext->uc_mcontext.__gregs[_REG_ERR];
# elif SANITIZER_HAIKU
uptr err = ucontext->uc_mcontext.r13;
# elif SANITIZER_SOLARIS && defined(__i386__)
const int Err = 13;
uptr err = ucontext->uc_mcontext.gregs[Err];
@ -2598,6 +2600,11 @@ static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
*pc = ucontext->uc_mcontext.mc_rip;
*bp = ucontext->uc_mcontext.mc_rbp;
*sp = ucontext->uc_mcontext.mc_rsp;
# elif SANITIZER_HAIKU
ucontext_t *ucontext = (ucontext_t *)context;
*pc = ucontext->uc_mcontext.rip;
*bp = ucontext->uc_mcontext.rbp;
*sp = ucontext->uc_mcontext.rsp;
# else
ucontext_t *ucontext = (ucontext_t *)context;
*pc = ucontext->uc_mcontext.gregs[REG_RIP];

View file

@ -14,7 +14,7 @@
#include "sanitizer_platform.h"
#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \
SANITIZER_SOLARIS
SANITIZER_SOLARIS || SANITIZER_HAIKU
# include "sanitizer_common.h"
# include "sanitizer_internal_defs.h"
# include "sanitizer_platform_limits_freebsd.h"
@ -31,6 +31,11 @@ namespace __sanitizer {
// the one in <dirent.h>, which is used by readdir().
struct linux_dirent;
# if SANITIZER_HAIKU
struct MemoryMappingLayoutData {
long signed int cookie;
};
# else
struct ProcSelfMapsBuff {
char *data;
uptr mmaped_size;
@ -43,6 +48,7 @@ struct MemoryMappingLayoutData {
};
void ReadProcMaps(ProcSelfMapsBuff *proc_maps);
# endif // SANITIZER_HAIKU
// Syscall wrappers.
uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count);
@ -124,7 +130,7 @@ bool LibraryNameIs(const char *full_name, const char *base_name);
// Call cb for each region mapped by map.
void ForEachMappedRegion(link_map *map, void (*cb)(const void *, uptr));
// Releases memory pages entirely within the [beg, end] address range.
// Releases memory pages entirely within the [beg, end) address range.
// The pages no longer count toward RSS; reads are guaranteed to return 0.
// Requires (but does not verify!) that pages are MAP_PRIVATE.
inline void ReleaseMemoryPagesToOSAndZeroFill(uptr beg, uptr end) {

View file

@ -14,7 +14,7 @@
#include "sanitizer_platform.h"
#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \
SANITIZER_SOLARIS
SANITIZER_SOLARIS || SANITIZER_HAIKU
# include "sanitizer_allocator_internal.h"
# include "sanitizer_atomic.h"
@ -28,8 +28,19 @@
# include "sanitizer_procmaps.h"
# include "sanitizer_solaris.h"
# if SANITIZER_HAIKU
# define _DEFAULT_SOURCE
# endif
# if SANITIZER_NETBSD
# define _RTLD_SOURCE // for __lwp_gettcb_fast() / __lwp_getprivate_fast()
# // for __lwp_gettcb_fast() / __lwp_getprivate_fast()
# define _RTLD_SOURCE
# include <machine/mcontext.h>
# undef _RTLD_SOURCE
# include <sys/param.h>
# if __NetBSD_Version__ >= 1099001200
# include <machine/lwp_private.h>
# endif
# endif
# include <dlfcn.h> // for dlsym()
@ -74,18 +85,9 @@ extern "C" int __sys_sigaction(int signum, const struct sigaction *act,
# include <thread.h>
# endif
# if SANITIZER_ANDROID
# include <android/api-level.h>
# if !defined(CPU_COUNT) && !defined(__aarch64__)
# include <dirent.h>
# include <fcntl.h>
struct __sanitizer::linux_dirent {
long d_ino;
off_t d_off;
unsigned short d_reclen;
char d_name[];
};
# endif
# if SANITIZER_HAIKU
# include <kernel/OS.h>
# include <sys/link_elf.h>
# endif
# if !SANITIZER_ANDROID
@ -651,6 +653,7 @@ static void GetTls(uptr *addr, uptr *size) {
*addr = (uptr)tcb->tcb_dtv[1];
}
}
# elif SANITIZER_HAIKU
# else
# error "Unknown OS"
# endif
@ -721,8 +724,13 @@ static int AddModuleSegments(const char *module_name, dl_phdr_info *info,
if (phdr->p_type == PT_LOAD) {
uptr cur_beg = info->dlpi_addr + phdr->p_vaddr;
uptr cur_end = cur_beg + phdr->p_memsz;
# if SANITIZER_HAIKU
bool executable = phdr->p_flags & PF_EXECUTE;
bool writable = phdr->p_flags & PF_WRITE;
# else
bool executable = phdr->p_flags & PF_X;
bool writable = phdr->p_flags & PF_W;
# endif
cur_module.addAddressRange(cur_beg, cur_end, executable, writable);
} else if (phdr->p_type == PT_NOTE) {
# ifdef NT_GNU_BUILD_ID
@ -774,42 +782,13 @@ static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) {
return 0;
}
static bool requiresProcmaps() {
# if SANITIZER_ANDROID && __ANDROID_API__ <= 22
// Fall back to /proc/maps if dl_iterate_phdr is unavailable or broken.
// The runtime check allows the same library to work with
// both K and L (and future) Android releases.
return AndroidGetApiLevel() <= ANDROID_LOLLIPOP_MR1;
# else
return false;
# endif
}
static void procmapsInit(InternalMmapVectorNoCtor<LoadedModule> *modules) {
MemoryMappingLayout memory_mapping(/*cache_enabled*/ true);
memory_mapping.DumpListOfModules(modules);
}
void ListOfModules::init() {
clearOrInit();
if (requiresProcmaps()) {
procmapsInit(&modules_);
} else {
DlIteratePhdrData data = {&modules_, true};
dl_iterate_phdr(dl_iterate_phdr_cb, &data);
}
}
// When a custom loader is used, dl_iterate_phdr may not contain the full
// list of modules. Allow callers to fall back to using procmaps.
void ListOfModules::fallbackInit() {
if (!requiresProcmaps()) {
clearOrInit();
procmapsInit(&modules_);
} else {
clear();
}
}
void ListOfModules::fallbackInit() { clear(); }
// getrusage does not give us the current RSS, only the max RSS.
// Still, this is better than nothing if /proc/self/statm is not available
@ -855,45 +834,17 @@ u32 GetNumberOfCPUs() {
int req[2];
uptr len = sizeof(ncpu);
req[0] = CTL_HW;
# ifdef HW_NCPUONLINE
req[1] = HW_NCPUONLINE;
# else
req[1] = HW_NCPU;
# endif
CHECK_EQ(internal_sysctl(req, 2, &ncpu, &len, NULL, 0), 0);
return ncpu;
# elif SANITIZER_ANDROID && !defined(CPU_COUNT) && !defined(__aarch64__)
// Fall back to /sys/devices/system/cpu on Android when cpu_set_t doesn't
// exist in sched.h. That is the case for toolchains generated with older
// NDKs.
// This code doesn't work on AArch64 because internal_getdents makes use of
// the 64bit getdents syscall, but cpu_set_t seems to always exist on AArch64.
uptr fd = internal_open("/sys/devices/system/cpu", O_RDONLY | O_DIRECTORY);
if (internal_iserror(fd))
return 0;
InternalMmapVector<u8> buffer(4096);
uptr bytes_read = buffer.size();
uptr n_cpus = 0;
u8 *d_type;
struct linux_dirent *entry = (struct linux_dirent *)&buffer[bytes_read];
while (true) {
if ((u8 *)entry >= &buffer[bytes_read]) {
bytes_read = internal_getdents(fd, (struct linux_dirent *)buffer.data(),
buffer.size());
if (internal_iserror(bytes_read) || !bytes_read)
break;
entry = (struct linux_dirent *)buffer.data();
}
d_type = (u8 *)entry + entry->d_reclen - 1;
if (d_type >= &buffer[bytes_read] ||
(u8 *)&entry->d_name[3] >= &buffer[bytes_read])
break;
if (entry->d_ino != 0 && *d_type == DT_DIR) {
if (entry->d_name[0] == 'c' && entry->d_name[1] == 'p' &&
entry->d_name[2] == 'u' && entry->d_name[3] >= '0' &&
entry->d_name[3] <= '9')
n_cpus++;
}
entry = (struct linux_dirent *)(((u8 *)entry) + entry->d_reclen);
}
internal_close(fd);
return n_cpus;
# elif SANITIZER_HAIKU
system_info info;
get_system_info(&info);
return info.cpu_count;
# elif SANITIZER_SOLARIS
return sysconf(_SC_NPROCESSORS_ONLN);
# else

View file

@ -38,13 +38,6 @@
extern char **environ;
# endif
# if defined(__has_include) && __has_include(<os/trace.h>)
# define SANITIZER_OS_TRACE 1
# include <os/trace.h>
# else
# define SANITIZER_OS_TRACE 0
# endif
// Integrate with CrashReporter library if available
# if defined(__has_include) && __has_include(<CrashReporterClient.h>)
# define HAVE_CRASHREPORTERCLIENT_H 1
@ -843,31 +836,23 @@ void LogMessageOnPrintf(const char *str) {
}
void LogFullErrorReport(const char *buffer) {
#if !SANITIZER_GO
// Log with os_trace. This will make it into the crash log.
#if SANITIZER_OS_TRACE
#pragma clang diagnostic push
// os_trace is deprecated.
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
if (GetMacosAlignedVersion() >= MacosVersion(10, 10)) {
// os_trace requires the message (format parameter) to be a string literal.
# if !SANITIZER_GO
// Log with os_log_error. This will make it into the crash log.
if (internal_strncmp(SanitizerToolName, "AddressSanitizer",
sizeof("AddressSanitizer") - 1) == 0)
os_trace("Address Sanitizer reported a failure.");
os_log_error(OS_LOG_DEFAULT, "Address Sanitizer reported a failure.");
else if (internal_strncmp(SanitizerToolName, "UndefinedBehaviorSanitizer",
sizeof("UndefinedBehaviorSanitizer") - 1) == 0)
os_trace("Undefined Behavior Sanitizer reported a failure.");
os_log_error(OS_LOG_DEFAULT,
"Undefined Behavior Sanitizer reported a failure.");
else if (internal_strncmp(SanitizerToolName, "ThreadSanitizer",
sizeof("ThreadSanitizer") - 1) == 0)
os_trace("Thread Sanitizer reported a failure.");
os_log_error(OS_LOG_DEFAULT, "Thread Sanitizer reported a failure.");
else
os_trace("Sanitizer tool reported a failure.");
os_log_error(OS_LOG_DEFAULT, "Sanitizer tool reported a failure.");
if (common_flags()->log_to_syslog)
os_trace("Consult syslog for more information.");
}
#pragma clang diagnostic pop
#endif
os_log_error(OS_LOG_DEFAULT, "Consult syslog for more information.");
// Log to syslog.
// The logging on OS X may call pthread_create so we need the threading
@ -881,7 +866,7 @@ void LogFullErrorReport(const char *buffer) {
WriteToSyslog(buffer);
// The report is added to CrashLog as part of logging all of Printf output.
#endif
# endif // !SANITIZER_GO
}
SignalContext::WriteFlag SignalContext::GetWriteFlag() const {
@ -1203,13 +1188,14 @@ uptr MapDynamicShadow(uptr shadow_size_bytes, uptr shadow_scale,
const uptr left_padding =
Max<uptr>(granularity, 1ULL << min_shadow_base_alignment);
uptr space_size = shadow_size_bytes + left_padding;
uptr space_size = shadow_size_bytes;
uptr largest_gap_found = 0;
uptr max_occupied_addr = 0;
VReport(2, "FindDynamicShadowStart, space_size = %p\n", (void *)space_size);
uptr shadow_start =
FindAvailableMemoryRange(space_size, alignment, granularity,
FindAvailableMemoryRange(space_size, alignment, left_padding,
&largest_gap_found, &max_occupied_addr);
// If the shadow doesn't fit, restrict the address space to make it fit.
if (shadow_start == 0) {
@ -1229,9 +1215,9 @@ uptr MapDynamicShadow(uptr shadow_size_bytes, uptr shadow_scale,
}
RestrictMemoryToMaxAddress(new_max_vm);
high_mem_end = new_max_vm - 1;
space_size = (high_mem_end >> shadow_scale) + left_padding;
space_size = (high_mem_end >> shadow_scale);
VReport(2, "FindDynamicShadowStart, space_size = %p\n", (void *)space_size);
shadow_start = FindAvailableMemoryRange(space_size, alignment, granularity,
shadow_start = FindAvailableMemoryRange(space_size, alignment, left_padding,
nullptr, nullptr);
if (shadow_start == 0) {
Report("Unable to find a memory range after restricting VM.\n");
@ -1272,10 +1258,15 @@ uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding,
mach_msg_type_number_t count = kRegionInfoSize;
kr = mach_vm_region_recurse(mach_task_self(), &address, &vmsize, &depth,
(vm_region_info_t)&vminfo, &count);
if (kr == KERN_INVALID_ADDRESS) {
// There are cases where going beyond the processes' max vm does
// not return KERN_INVALID_ADDRESS so we check for going beyond that
// max address as well.
if (kr == KERN_INVALID_ADDRESS || address > max_vm_address) {
// No more regions beyond "address", consider the gap at the end of VM.
address = max_vm_address;
vmsize = 0;
kr = -1; // break after this iteration.
} else {
if (max_occupied_addr) *max_occupied_addr = address + vmsize;
}

View file

@ -37,9 +37,6 @@ struct VersionBase {
VersionBase(u16 major, u16 minor) : major(major), minor(minor) {}
bool operator==(const VersionType &other) const {
return major == other.major && minor == other.minor;
}
bool operator>=(const VersionType &other) const {
return major > other.major ||
(major == other.major && minor >= other.minor);
@ -47,6 +44,12 @@ struct VersionBase {
bool operator<(const VersionType &other) const { return !(*this >= other); }
};
template <typename VersionType>
bool operator==(const VersionBase<VersionType> &self,
const VersionBase<VersionType> &other) {
return self.major == other.major && self.minor == other.minor;
}
struct MacosVersion : VersionBase<MacosVersion> {
MacosVersion(u16 major, u16 minor) : VersionBase(major, minor) {}
};

View file

@ -144,6 +144,22 @@ INTERCEPTOR(void, free, void *ptr) {
COMMON_MALLOC_FREE(ptr);
}
#if SANITIZER_INTERCEPT_FREE_SIZED && defined(COMMON_MALLOC_FREE_SIZED)
INTERCEPTOR(void, free_sized, void *ptr, size_t size) {
COMMON_MALLOC_ENTER();
COMMON_MALLOC_FREE_SIZED(ptr, size);
}
#endif
#if SANITIZER_INTERCEPT_FREE_ALIGNED_SIZED && \
defined(COMMON_MALLOC_FREE_ALIGNED_SIZED)
INTERCEPTOR(void, free_aligned_sized, void *ptr, size_t alignment,
size_t size) {
COMMON_MALLOC_ENTER();
COMMON_MALLOC_FREE_ALIGNED_SIZED(ptr, alignment, size);
}
#endif
INTERCEPTOR(void *, realloc, void *ptr, size_t size) {
COMMON_MALLOC_ENTER();
COMMON_MALLOC_REALLOC(ptr, size);

View file

@ -14,7 +14,8 @@
#if !defined(__linux__) && !defined(__FreeBSD__) && !defined(__NetBSD__) && \
!defined(__APPLE__) && !defined(_WIN32) && !defined(__Fuchsia__) && \
!(defined(__sun__) && defined(__svr4__))
!(defined(__sun__) && defined(__svr4__)) && !defined(__HAIKU__) && \
!defined(__wasi__)
# error "This operating system is not supported"
#endif
@ -55,6 +56,18 @@
# define SANITIZER_SOLARIS 0
#endif
#if defined(__HAIKU__)
# define SANITIZER_HAIKU 1
#else
# define SANITIZER_HAIKU 0
#endif
#if defined(__wasi__)
# define SANITIZER_WASI 1
#else
# define SANITIZER_WASI 0
#endif
// - SANITIZER_APPLE: all Apple code
// - TARGET_OS_OSX: macOS
// - SANITIZER_IOS: devices (iOS and iOS-like)
@ -138,7 +151,7 @@
#define SANITIZER_POSIX \
(SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_APPLE || \
SANITIZER_NETBSD || SANITIZER_SOLARIS)
SANITIZER_NETBSD || SANITIZER_SOLARIS || SANITIZER_HAIKU)
#if __LP64__ || defined(_WIN64)
# define SANITIZER_WORDSIZE 64
@ -305,6 +318,9 @@
# endif
#endif
// The first address that can be returned by mmap.
#define SANITIZER_MMAP_BEGIN 0
// The range of addresses which can be returned my mmap.
// FIXME: this value should be different on different platforms. Larger values
// will still work but will consume more memory for TwoLevelByteMap.
@ -410,7 +426,8 @@
# define SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT 0
#endif
#if SANITIZER_FREEBSD || SANITIZER_APPLE || SANITIZER_NETBSD || SANITIZER_SOLARIS
#if SANITIZER_FREEBSD || SANITIZER_APPLE || SANITIZER_NETBSD || \
SANITIZER_SOLARIS || SANITIZER_HAIKU
# define SANITIZER_MADVISE_DONTNEED MADV_FREE
#else
# define SANITIZER_MADVISE_DONTNEED MADV_DONTNEED

View file

@ -129,8 +129,10 @@ SANITIZER_WEAK_IMPORT void *aligned_alloc(__sanitizer::usize __alignment,
#if SANITIZER_FUCHSIA
#define SI_NOT_FUCHSIA 0
#define SI_FUCHSIA 1
#else
#define SI_NOT_FUCHSIA 1
#define SI_FUCHSIA 0
#endif
#if SANITIZER_SOLARIS
@ -139,6 +141,12 @@ SANITIZER_WEAK_IMPORT void *aligned_alloc(__sanitizer::usize __alignment,
#define SI_SOLARIS 0
#endif
#if SANITIZER_AIX
# define SI_NOT_AIX 0
#else
# define SI_NOT_AIX 1
#endif
#if SANITIZER_SOLARIS32
#define SI_SOLARIS32 1
#else
@ -159,20 +167,20 @@ SANITIZER_WEAK_IMPORT void *aligned_alloc(__sanitizer::usize __alignment,
#define SANITIZER_INTERCEPT_STRLEN SI_NOT_FUCHSIA
#define SANITIZER_INTERCEPT_STRNLEN (SI_NOT_MAC && SI_NOT_FUCHSIA)
#define SANITIZER_INTERCEPT_STRCMP SI_NOT_FUCHSIA
#define SANITIZER_INTERCEPT_STRCMP (SI_NOT_FUCHSIA && SI_NOT_AIX)
#define SANITIZER_INTERCEPT_STRSTR SI_NOT_FUCHSIA
#define SANITIZER_INTERCEPT_STRCASESTR SI_POSIX
#define SANITIZER_INTERCEPT_STRCASESTR (SI_POSIX && SI_NOT_AIX)
#define SANITIZER_INTERCEPT_STRTOK SI_NOT_FUCHSIA
#define SANITIZER_INTERCEPT_STRCHR SI_NOT_FUCHSIA
#define SANITIZER_INTERCEPT_STRCHRNUL SI_POSIX_NOT_MAC
#define SANITIZER_INTERCEPT_STRCHRNUL (SI_POSIX_NOT_MAC && SI_NOT_AIX)
#define SANITIZER_INTERCEPT_STRRCHR SI_NOT_FUCHSIA
#define SANITIZER_INTERCEPT_STRSPN SI_NOT_FUCHSIA
#define SANITIZER_INTERCEPT_STRPBRK SI_NOT_FUCHSIA
#define SANITIZER_INTERCEPT_TEXTDOMAIN SI_LINUX_NOT_ANDROID || SI_SOLARIS
#define SANITIZER_INTERCEPT_STRCASECMP SI_POSIX
#define SANITIZER_INTERCEPT_MEMSET 1
#define SANITIZER_INTERCEPT_MEMMOVE 1
#define SANITIZER_INTERCEPT_MEMCPY 1
#define SANITIZER_INTERCEPT_MEMMOVE SI_NOT_AIX
#define SANITIZER_INTERCEPT_MEMCPY SI_NOT_AIX
#define SANITIZER_INTERCEPT_MEMCMP SI_NOT_FUCHSIA
#define SANITIZER_INTERCEPT_BCMP \
SANITIZER_INTERCEPT_MEMCMP && \
@ -231,16 +239,22 @@ SANITIZER_WEAK_IMPORT void *aligned_alloc(__sanitizer::usize __alignment,
#define SANITIZER_INTERCEPT_ISOC99_SCANF SI_GLIBC
#ifndef SANITIZER_INTERCEPT_PRINTF
#define SANITIZER_INTERCEPT_PRINTF SI_POSIX
#define SANITIZER_INTERCEPT_PRINTF_L (SI_FREEBSD || SI_NETBSD)
#define SANITIZER_INTERCEPT_ISOC99_PRINTF SI_GLIBC
# define SANITIZER_INTERCEPT_ASPRINTF SI_NOT_AIX
# define SANITIZER_INTERCEPT_VASPRINTF SI_NOT_AIX
# define SANITIZER_INTERCEPT_PRINTF SI_POSIX
# define SANITIZER_INTERCEPT_PRINTF_L (SI_FREEBSD || SI_NETBSD)
# define SANITIZER_INTERCEPT_ISOC99_PRINTF SI_GLIBC
#endif
#define SANITIZER_INTERCEPT_SETPROCTITLE (SI_FREEBSD || SI_NETBSD)
#define SANITIZER_INTERCEPT___PRINTF_CHK \
(SANITIZER_INTERCEPT_PRINTF && SI_GLIBC)
#define SANITIZER_INTERCEPT_FREXP SI_NOT_FUCHSIA
#define SANITIZER_INTERCEPT_FREXPF_FREXPL SI_POSIX
// AIX libc does not export FREXP and FREXPF.
#define SANITIZER_INTERCEPT_FREXP (SI_NOT_FUCHSIA && SI_NOT_AIX)
#define SANITIZER_INTERCEPT_FREXPF (SI_POSIX && SI_NOT_AIX)
#define SANITIZER_INTERCEPT_FREXPL SI_POSIX
#define SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS SI_POSIX
#define SANITIZER_INTERCEPT_GETPWNAM_R_AND_FRIENDS \
@ -289,7 +303,7 @@ SANITIZER_WEAK_IMPORT void *aligned_alloc(__sanitizer::usize __alignment,
#define SANITIZER_INTERCEPT_ACCEPT4 \
(SI_LINUX_NOT_ANDROID || SI_NETBSD || SI_FREEBSD)
#define SANITIZER_INTERCEPT_PACCEPT SI_NETBSD
#define SANITIZER_INTERCEPT_MODF SI_POSIX
#define SANITIZER_INTERCEPT_MODF (SI_POSIX && SI_NOT_AIX)
#define SANITIZER_INTERCEPT_RECVMSG SI_POSIX
#define SANITIZER_INTERCEPT_SENDMSG SI_POSIX
#define SANITIZER_INTERCEPT_RECVMMSG SI_LINUX
@ -325,7 +339,8 @@ SANITIZER_WEAK_IMPORT void *aligned_alloc(__sanitizer::usize __alignment,
#define SANITIZER_INTERCEPT_WCSNRTOMBS \
(SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
#define SANITIZER_INTERCEPT_WCRTOMB \
(SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
(SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS || \
!SI_NOT_AIX)
#define SANITIZER_INTERCEPT_WCTOMB \
(SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
#define SANITIZER_INTERCEPT_TCGETATTR SI_LINUX_NOT_ANDROID || SI_SOLARIS
@ -365,7 +380,8 @@ SANITIZER_WEAK_IMPORT void *aligned_alloc(__sanitizer::usize __alignment,
#define SANITIZER_INTERCEPT_GETMNTENT_R SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_STATFS \
(SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
#define SANITIZER_INTERCEPT_STATFS64 SI_GLIBC && SANITIZER_HAS_STATFS64
#define SANITIZER_INTERCEPT_STATFS64 \
((SI_GLIBC || !SI_NOT_AIX) && SANITIZER_HAS_STATFS64)
#define SANITIZER_INTERCEPT_STATVFS \
(SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID)
#define SANITIZER_INTERCEPT_STATVFS64 SI_GLIBC
@ -414,10 +430,10 @@ SANITIZER_WEAK_IMPORT void *aligned_alloc(__sanitizer::usize __alignment,
#define SANITIZER_INTERCEPT_TTYNAME_R SI_POSIX
#define SANITIZER_INTERCEPT_TEMPNAM SI_POSIX
#define SANITIZER_INTERCEPT_SINCOS SI_LINUX || SI_SOLARIS
#define SANITIZER_INTERCEPT_REMQUO SI_POSIX
#define SANITIZER_INTERCEPT_REMQUOL (SI_POSIX && !SI_NETBSD)
#define SANITIZER_INTERCEPT_LGAMMA SI_POSIX
#define SANITIZER_INTERCEPT_LGAMMAL (SI_POSIX && !SI_NETBSD)
#define SANITIZER_INTERCEPT_REMQUO (SI_POSIX && SI_NOT_AIX)
#define SANITIZER_INTERCEPT_REMQUOL (SI_POSIX && !SI_NETBSD && SI_NOT_AIX)
#define SANITIZER_INTERCEPT_LGAMMA (SI_POSIX && SI_NOT_AIX)
#define SANITIZER_INTERCEPT_LGAMMAL (SI_POSIX && !SI_NETBSD && SI_NOT_AIX)
#define SANITIZER_INTERCEPT_LGAMMA_R (SI_FREEBSD || SI_LINUX || SI_SOLARIS)
#define SANITIZER_INTERCEPT_LGAMMAL_R SI_LINUX_NOT_ANDROID || SI_SOLARIS
#define SANITIZER_INTERCEPT_DRAND48_R SI_GLIBC
@ -502,9 +518,11 @@ SANITIZER_WEAK_IMPORT void *aligned_alloc(__sanitizer::usize __alignment,
#define SI_STAT_LINUX (SI_LINUX && __GLIBC_PREREQ(2, 33))
#define SANITIZER_INTERCEPT_STAT \
(SI_FREEBSD || SI_MAC || SI_ANDROID || SI_NETBSD || SI_SOLARIS || \
SI_STAT_LINUX)
#define SANITIZER_INTERCEPT_STAT64 SI_STAT_LINUX && SANITIZER_HAS_STAT64
#define SANITIZER_INTERCEPT_LSTAT (SI_NETBSD || SI_FREEBSD || SI_STAT_LINUX)
SI_STAT_LINUX || !SI_NOT_AIX)
#define SANITIZER_INTERCEPT_STAT64 \
((SI_STAT_LINUX || !SI_NOT_AIX) && SANITIZER_HAS_STAT64)
#define SANITIZER_INTERCEPT_LSTAT \
(SI_NETBSD || SI_FREEBSD || SI_STAT_LINUX || !SI_NOT_AIX)
#define SANITIZER_INTERCEPT___XSTAT \
((!SANITIZER_INTERCEPT_STAT && SI_POSIX) || SI_STAT_LINUX)
#define SANITIZER_INTERCEPT___XSTAT64 SI_GLIBC
@ -521,7 +539,8 @@ SANITIZER_WEAK_IMPORT void *aligned_alloc(__sanitizer::usize __alignment,
#define SANITIZER_INTERCEPT_MMAP SI_POSIX
#define SANITIZER_INTERCEPT_MMAP64 SI_GLIBC || SI_SOLARIS
#define SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO (SI_GLIBC || SI_ANDROID)
#define SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO \
(SI_GLIBC || SI_ANDROID || SI_FUCHSIA)
#define SANITIZER_INTERCEPT_MEMALIGN (!SI_FREEBSD && !SI_MAC && !SI_NETBSD)
#define SANITIZER_INTERCEPT___LIBC_MEMALIGN SI_GLIBC
#define SANITIZER_INTERCEPT_PVALLOC (SI_GLIBC || SI_ANDROID)
@ -572,7 +591,7 @@ SANITIZER_WEAK_IMPORT void *aligned_alloc(__sanitizer::usize __alignment,
#define SANITIZER_INTERCEPT_PROTOENT_R SI_GLIBC
#define SANITIZER_INTERCEPT_NETENT (SI_LINUX || SI_NETBSD || SI_FREEBSD)
#define SANITIZER_INTERCEPT_SETVBUF \
(SI_NETBSD || SI_FREEBSD || SI_LINUX || SI_MAC)
(SI_NETBSD || SI_FREEBSD || SI_LINUX || SI_MAC || !SI_NOT_AIX)
#define SANITIZER_INTERCEPT_GETMNTINFO (SI_NETBSD || SI_FREEBSD || SI_MAC)
#define SANITIZER_INTERCEPT_MI_VECTOR_HASH SI_NETBSD
#define SANITIZER_INTERCEPT_GETVFSSTAT SI_NETBSD
@ -640,6 +659,21 @@ SANITIZER_WEAK_IMPORT void *aligned_alloc(__sanitizer::usize __alignment,
# define SI_MAC_OS_DEPLOYMENT_MIN_13_00 0
#endif
#define SANITIZER_INTERCEPT_FREADLINK (SI_MAC && SI_MAC_OS_DEPLOYMENT_MIN_13_00)
#define SANITIZER_INTERCEPT_GETSERVENT_R SI_GLIBC
#define SANITIZER_INTERCEPT_GETSERVBYNAME_R SI_GLIBC
#define SANITIZER_INTERCEPT_GETSERVBYPORT_R SI_GLIBC
// Until free_sized and free_aligned_sized are more generally available,
// we can only unconditionally intercept on ELF-based platforms where it
// is okay to have undefined weak symbols.
#ifdef __ELF__
# define SANITIZER_INTERCEPT_FREE_SIZED 1
# define SANITIZER_INTERCEPT_FREE_ALIGNED_SIZED 1
#else
# define SANITIZER_INTERCEPT_FREE_SIZED 0
# define SANITIZER_INTERCEPT_FREE_ALIGNED_SIZED 0
#endif
// This macro gives a way for downstream users to override the above
// interceptor macros irrespective of the platform they are on. They have
// to do two things:

View file

@ -29,6 +29,7 @@
#include <sys/mtio.h>
#include <sys/ptrace.h>
#include <sys/resource.h>
#include <sys/shm.h>
#include <sys/signal.h>
#include <sys/socket.h>
#include <sys/sockio.h>
@ -81,10 +82,6 @@
#include <wchar.h>
#include <wordexp.h>
#define _KERNEL // to declare 'shminfo' structure
#include <sys/shm.h>
#undef _KERNEL
#undef IOC_DIRMASK
// Include these after system headers to avoid name clashes and ambiguities.
@ -135,8 +132,6 @@ 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);
@ -150,9 +145,6 @@ const uptr sig_err = (uptr)SIG_ERR;
const uptr sa_siginfo = (uptr)SA_SIGINFO;
int shmctl_ipc_stat = (int)IPC_STAT;
int shmctl_ipc_info = (int)IPC_INFO;
int shmctl_shm_info = (int)SHM_INFO;
int shmctl_shm_stat = (int)SHM_STAT;
unsigned struct_utmpx_sz = sizeof(struct utmpx);
int map_fixed = MAP_FIXED;

View file

@ -419,12 +419,14 @@ struct __sanitizer_wordexp_t {
typedef void __sanitizer_FILE;
extern unsigned struct_shminfo_sz;
extern unsigned struct_shm_info_sz;
extern int shmctl_ipc_stat;
extern int shmctl_ipc_info;
extern int shmctl_shm_info;
extern int shmctl_shm_stat;
// This simplifies generic code
#define struct_shminfo_sz -1
#define struct_shm_info_sz -1
#define shmctl_shm_stat -1
#define shmctl_ipc_info -1
#define shmctl_shm_info -1
extern unsigned struct_utmpx_sz;

View file

@ -24,7 +24,7 @@
// Must go after undef _FILE_OFFSET_BITS.
#include "sanitizer_platform.h"
#if SANITIZER_LINUX || SANITIZER_APPLE
#if SANITIZER_LINUX || SANITIZER_APPLE || SANITIZER_HAIKU
// Must go after undef _FILE_OFFSET_BITS.
#include "sanitizer_glibc_version.h"
@ -52,7 +52,7 @@
#include <time.h>
#include <wchar.h>
#include <regex.h>
#if !SANITIZER_APPLE
#if !SANITIZER_APPLE && !SANITIZER_HAIKU
#include <utmp.h>
#endif
@ -61,7 +61,9 @@
#endif
#if !SANITIZER_ANDROID
#if !SANITIZER_HAIKU
#include <sys/mount.h>
#endif
#include <sys/timeb.h>
#include <utmpx.h>
#endif
@ -111,9 +113,11 @@ typedef struct user_fpregs elf_fpregset_t;
#if !SANITIZER_ANDROID
#include <ifaddrs.h>
#if !SANITIZER_HAIKU
#include <sys/ucontext.h>
#include <wordexp.h>
#endif
#endif
#if SANITIZER_LINUX
#if SANITIZER_GLIBC
@ -163,7 +167,7 @@ typedef struct user_fpregs elf_fpregset_t;
#include <sys/vfs.h>
#include <sys/epoll.h>
#include <linux/capability.h>
#else
#elif !SANITIZER_HAIKU
#include <fstab.h>
#endif // SANITIZER_LINUX
@ -173,6 +177,11 @@ typedef struct user_fpregs elf_fpregset_t;
#include <sys/sockio.h>
#endif
#if SANITIZER_HAIKU
#include <sys/sockio.h>
#include <sys/ioctl.h>
#endif
// Include these after system headers to avoid name clashes and ambiguities.
# include "sanitizer_common.h"
# include "sanitizer_internal_defs.h"
@ -217,7 +226,7 @@ namespace __sanitizer {
unsigned struct_fstab_sz = sizeof(struct fstab);
#endif // SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD ||
// SANITIZER_APPLE
#if !SANITIZER_ANDROID
#if !SANITIZER_ANDROID && !SANITIZER_HAIKU
unsigned struct_statfs_sz = sizeof(struct statfs);
unsigned struct_sockaddr_sz = sizeof(struct sockaddr);
@ -324,7 +333,7 @@ namespace __sanitizer {
int shmctl_shm_stat = (int)SHM_STAT;
#endif
#if !SANITIZER_APPLE && !SANITIZER_FREEBSD
#if !SANITIZER_APPLE && !SANITIZER_FREEBSD && !SANITIZER_HAIKU
unsigned struct_utmp_sz = sizeof(struct utmp);
#endif
#if !SANITIZER_ANDROID
@ -356,9 +365,9 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
int glob_altdirfunc = GLOB_ALTDIRFUNC;
#endif
# if !SANITIZER_ANDROID
# if !SANITIZER_ANDROID && !SANITIZER_HAIKU
const int wordexp_wrde_dooffs = WRDE_DOOFFS;
# endif // !SANITIZER_ANDROID
# endif // !SANITIZER_ANDROID && !SANITIZER_HAIKU
# if SANITIZER_LINUX && !SANITIZER_ANDROID && \
(defined(__i386) || defined(__x86_64) || defined(__mips64) || \
@ -537,7 +546,7 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
unsigned struct_sock_fprog_sz = sizeof(struct sock_fprog);
# endif // SANITIZER_GLIBC
# if !SANITIZER_ANDROID && !SANITIZER_APPLE
# if !SANITIZER_ANDROID && !SANITIZER_APPLE && !SANITIZER_HAIKU
unsigned struct_sioc_sg_req_sz = sizeof(struct sioc_sg_req);
unsigned struct_sioc_vif_req_sz = sizeof(struct sioc_vif_req);
#endif
@ -548,12 +557,14 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
const unsigned IOCTL_NOT_PRESENT = 0;
unsigned IOCTL_FIONBIO = FIONBIO;
#if !SANITIZER_HAIKU
unsigned IOCTL_FIOASYNC = FIOASYNC;
unsigned IOCTL_FIOCLEX = FIOCLEX;
unsigned IOCTL_FIOGETOWN = FIOGETOWN;
unsigned IOCTL_FIONBIO = FIONBIO;
unsigned IOCTL_FIONCLEX = FIONCLEX;
unsigned IOCTL_FIOSETOWN = FIOSETOWN;
#endif
unsigned IOCTL_SIOCADDMULTI = SIOCADDMULTI;
unsigned IOCTL_SIOCATMARK = SIOCATMARK;
unsigned IOCTL_SIOCDELMULTI = SIOCDELMULTI;
@ -574,23 +585,27 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
unsigned IOCTL_SIOCSIFMTU = SIOCSIFMTU;
unsigned IOCTL_SIOCSIFNETMASK = SIOCSIFNETMASK;
unsigned IOCTL_SIOCSPGRP = SIOCSPGRP;
#if !SANITIZER_HAIKU
unsigned IOCTL_TIOCCONS = TIOCCONS;
unsigned IOCTL_TIOCEXCL = TIOCEXCL;
unsigned IOCTL_TIOCGETD = TIOCGETD;
unsigned IOCTL_TIOCNOTTY = TIOCNOTTY;
unsigned IOCTL_TIOCPKT = TIOCPKT;
unsigned IOCTL_TIOCSETD = TIOCSETD;
unsigned IOCTL_TIOCSTI = TIOCSTI;
#endif
unsigned IOCTL_TIOCEXCL = TIOCEXCL;
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;
#if SANITIZER_LINUX && !SANITIZER_ANDROID
unsigned IOCTL_SIOCGETSGCNT = SIOCGETSGCNT;
@ -1100,7 +1115,7 @@ COMPILER_CHECK(sizeof(__sanitizer_dirent) <= sizeof(dirent));
CHECK_SIZE_AND_OFFSET(dirent, d_ino);
#if SANITIZER_APPLE
CHECK_SIZE_AND_OFFSET(dirent, d_seekoff);
#elif SANITIZER_FREEBSD
#elif SANITIZER_FREEBSD || SANITIZER_HAIKU
// There is no 'd_off' field on FreeBSD.
#else
CHECK_SIZE_AND_OFFSET(dirent, d_off);
@ -1116,7 +1131,9 @@ CHECK_SIZE_AND_OFFSET(dirent64, d_reclen);
CHECK_TYPE_SIZE(ifconf);
CHECK_SIZE_AND_OFFSET(ifconf, ifc_len);
#if !SANITIZER_HAIKU
CHECK_SIZE_AND_OFFSET(ifconf, ifc_ifcu);
#endif
CHECK_TYPE_SIZE(pollfd);
CHECK_SIZE_AND_OFFSET(pollfd, fd);
@ -1171,7 +1188,7 @@ CHECK_TYPE_SIZE(__kernel_loff_t);
CHECK_TYPE_SIZE(__kernel_fd_set);
#endif
#if !SANITIZER_ANDROID
#if !SANITIZER_ANDROID && !SANITIZER_HAIKU
CHECK_TYPE_SIZE(wordexp_t);
CHECK_SIZE_AND_OFFSET(wordexp_t, we_wordc);
CHECK_SIZE_AND_OFFSET(wordexp_t, we_wordv);
@ -1201,7 +1218,9 @@ CHECK_SIZE_AND_OFFSET(mntent, mnt_freq);
CHECK_SIZE_AND_OFFSET(mntent, mnt_passno);
#endif
#if !SANITIZER_HAIKU
CHECK_TYPE_SIZE(ether_addr);
#endif
#if SANITIZER_GLIBC || SANITIZER_FREEBSD
CHECK_TYPE_SIZE(ipc_perm);
@ -1239,7 +1258,7 @@ CHECK_TYPE_SIZE(clock_t);
CHECK_TYPE_SIZE(clockid_t);
#endif
#if !SANITIZER_ANDROID
#if !SANITIZER_ANDROID && !SANITIZER_HAIKU
CHECK_TYPE_SIZE(ifaddrs);
CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_next);
CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_name);

File diff suppressed because it is too large Load diff

View file

@ -16,7 +16,7 @@
#include "sanitizer_platform.h"
#if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || \
SANITIZER_APPLE || SANITIZER_SOLARIS || \
SANITIZER_APPLE || SANITIZER_SOLARIS || SANITIZER_HAIKU || \
SANITIZER_FUCHSIA
#include "sanitizer_common.h"

View file

@ -0,0 +1,94 @@
//===-- sanitizer_procmaps_haiku.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
// (Haiku-specific parts).
//===----------------------------------------------------------------------===//
#include "sanitizer_platform.h"
#if SANITIZER_HAIKU
# include "sanitizer_common.h"
# include "sanitizer_procmaps.h"
# include <kernel/OS.h>
namespace __sanitizer {
void MemoryMappedSegment::AddAddressRanges(LoadedModule *module) {
// data_ should be unused on this platform
CHECK(!data_);
module->addAddressRange(start, end, IsExecutable(), IsWritable());
}
MemoryMappingLayout::MemoryMappingLayout(bool) { Reset(); }
void MemoryMappingLayout::Reset() { data_.cookie = 0; }
MemoryMappingLayout::~MemoryMappingLayout() {}
// static
void MemoryMappingLayout::CacheMemoryMappings() {}
bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) {
area_info info;
if (get_next_area_info(B_CURRENT_TEAM, &data_.cookie, &info) != B_OK)
return false;
segment->start = (uptr)info.address;
segment->end = (uptr)info.address + info.size;
segment->offset = 0;
segment->protection = 0;
if (info.protection & B_READ_AREA)
segment->protection |= kProtectionRead;
if (info.protection & B_WRITE_AREA)
segment->protection |= kProtectionWrite;
if (info.protection & B_EXECUTE_AREA)
segment->protection |= kProtectionExecute;
if (segment->filename) {
uptr len = Min((uptr)B_OS_NAME_LENGTH, segment->filename_size - 1);
internal_strncpy(segment->filename, info.name, len);
segment->filename[len] = 0;
}
return true;
}
bool MemoryMappingLayout::Error() const { return false; }
void MemoryMappingLayout::DumpListOfModules(
InternalMmapVectorNoCtor<LoadedModule> *modules) {
Reset();
InternalMmapVector<char> module_name(kMaxPathLength);
MemoryMappedSegment segment(module_name.data(), module_name.size());
for (uptr i = 0; Next(&segment); i++) {
const char *cur_name = segment.filename;
if (cur_name[0] == '\0')
continue;
// Don't subtract 'cur_beg' from the first entry:
// * If a binary is compiled w/o -pie, then the first entry in
// process maps is likely the binary itself (all dynamic libs
// are mapped higher in address space). For such a binary,
// instruction offset in binary coincides with the actual
// instruction address in virtual memory (as code section
// is mapped to a fixed memory range).
// * If a binary is compiled with -pie, all the modules are
// mapped high at address space (in particular, higher than
// shadow memory of the tool), so the module can't be the
// first entry.
uptr base_address = (i ? segment.start : 0) - segment.offset;
LoadedModule cur_module;
cur_module.set(cur_name, base_address);
segment.AddAddressRanges(&cur_module);
modules->push_back(cur_module);
}
}
void GetMemoryProfile(fill_profile_f cb, uptr *stats) {}
} // namespace __sanitizer
#endif

View file

@ -334,9 +334,22 @@ static const load_command *NextCommand(const load_command *lc) {
return (const load_command *)((const char *)lc + lc->cmdsize);
}
static void FindUUID(const load_command *first_lc, u8 *uuid_output) {
for (const load_command *lc = first_lc; lc->cmd != 0; lc = NextCommand(lc)) {
if (lc->cmd != LC_UUID) continue;
# ifdef MH_MAGIC_64
static constexpr size_t header_size = sizeof(mach_header_64);
# else
static constexpr size_t header_size = sizeof(mach_header);
# endif
static void FindUUID(const load_command *first_lc, const mach_header *hdr,
u8 *uuid_output) {
uint32_t curcmd = 0;
for (const load_command *lc = first_lc; curcmd < hdr->ncmds;
curcmd++, lc = NextCommand(lc)) {
CHECK_LT((const char *)lc,
(const char *)hdr + header_size + hdr->sizeofcmds);
if (lc->cmd != LC_UUID)
continue;
const uuid_command *uuid_lc = (const uuid_command *)lc;
const uint8_t *uuid = &uuid_lc->uuid[0];
@ -345,9 +358,16 @@ static void FindUUID(const load_command *first_lc, u8 *uuid_output) {
}
}
static bool IsModuleInstrumented(const load_command *first_lc) {
for (const load_command *lc = first_lc; lc->cmd != 0; lc = NextCommand(lc)) {
if (lc->cmd != LC_LOAD_DYLIB) continue;
static bool IsModuleInstrumented(const load_command *first_lc,
const mach_header *hdr) {
uint32_t curcmd = 0;
for (const load_command *lc = first_lc; curcmd < hdr->ncmds;
curcmd++, lc = NextCommand(lc)) {
CHECK_LT((const char *)lc,
(const char *)hdr + header_size + hdr->sizeofcmds);
if (lc->cmd != LC_LOAD_DYLIB)
continue;
const dylib_command *dylib_lc = (const dylib_command *)lc;
uint32_t dylib_name_offset = dylib_lc->dylib.name.offset;
@ -393,10 +413,10 @@ bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) {
continue;
}
}
FindUUID((const load_command *)data_.current_load_cmd_addr,
FindUUID((const load_command *)data_.current_load_cmd_addr, hdr,
data_.current_uuid);
data_.current_instrumented = IsModuleInstrumented(
(const load_command *)data_.current_load_cmd_addr);
(const load_command *)data_.current_load_cmd_addr, hdr);
}
while (data_.current_load_cmd_count > 0) {

View file

@ -9,9 +9,6 @@
// Information about the process mappings (Solaris-specific parts).
//===----------------------------------------------------------------------===//
// Before Solaris 11.4, <procfs.h> doesn't work in a largefile environment.
#undef _FILE_OFFSET_BITS
// Avoid conflict between `_TIME_BITS` defined vs. `_FILE_OFFSET_BITS`
// undefined in some Linux configurations.
#undef _TIME_BITS

View file

@ -15,7 +15,7 @@
# define SANITIZER_REDEFINE_BUILTINS_H
// The asm hack only works with GCC and Clang.
# if !defined(_WIN32)
# if !defined(_WIN32) && !defined(_AIX)
asm(R"(
.set memcpy, __sanitizer_internal_memcpy

View file

@ -38,25 +38,28 @@
# include <asm/ptrace.h>
#endif
#include <sys/user.h> // for user_regs_struct
#if SANITIZER_ANDROID && SANITIZER_MIPS
# include <asm/reg.h> // for mips SP register in sys/user.h
#endif
#include <sys/wait.h> // for signal-related stuff
# if SANITIZER_MIPS
// clang-format off
# include <asm/sgidefs.h> // <asm/sgidefs.h> must be included before <asm/reg.h>
# include <asm/reg.h> // for mips SP register
// clang-format on
# endif
# include <sys/wait.h> // for signal-related stuff
#ifdef sa_handler
# ifdef sa_handler
# undef sa_handler
#endif
# endif
#ifdef sa_sigaction
# ifdef sa_sigaction
# undef sa_sigaction
#endif
# endif
#include "sanitizer_common.h"
#include "sanitizer_flags.h"
#include "sanitizer_libc.h"
#include "sanitizer_linux.h"
#include "sanitizer_mutex.h"
#include "sanitizer_placement_new.h"
# include "sanitizer_common.h"
# include "sanitizer_flags.h"
# include "sanitizer_libc.h"
# include "sanitizer_linux.h"
# include "sanitizer_mutex.h"
# include "sanitizer_placement_new.h"
// Sufficiently old kernel headers don't provide this value, but we can still
// call prctl with it. If the runtime kernel is new enough, the prctl call will
@ -511,11 +514,7 @@ typedef pt_regs regs_struct;
#elif defined(__mips__)
typedef struct user regs_struct;
# if SANITIZER_ANDROID
# define REG_SP regs[EF_R29]
# else
# define REG_SP regs[EF_REG29]
# endif
#elif defined(__aarch64__)
typedef struct user_pt_regs regs_struct;

View file

@ -49,6 +49,8 @@ struct SuspendedThreadsListWindows final : public SuspendedThreadsList {
# define SP_REG Esp
# elif SANITIZER_ARM | SANITIZER_ARM64
# define SP_REG Sp
# elif SANITIZER_MIPS32
# define SP_REG IntSp
# else
# error Architecture not supported!
# endif

View file

@ -31,11 +31,12 @@ Symbolizer *Symbolizer::GetOrInit() {
const char *ExtractToken(const char *str, const char *delims, char **result) {
uptr prefix_len = internal_strcspn(str, delims);
*result = (char*)InternalAlloc(prefix_len + 1);
*result = (char *)InternalAlloc(prefix_len + 1);
internal_memcpy(*result, str, prefix_len);
(*result)[prefix_len] = '\0';
const char *prefix_end = str + prefix_len;
if (*prefix_end != '\0') prefix_end++;
if (*prefix_end != '\0')
prefix_end++;
return prefix_end;
}
@ -78,7 +79,8 @@ const char *ExtractTokenUpToDelimiter(const char *str, const char *delimiter,
internal_memcpy(*result, str, prefix_len);
(*result)[prefix_len] = '\0';
const char *prefix_end = str + prefix_len;
if (*prefix_end != '\0') prefix_end += internal_strlen(delimiter);
if (*prefix_end != '\0')
prefix_end += internal_strlen(delimiter);
return prefix_end;
}
@ -215,18 +217,20 @@ const LoadedModule *Symbolizer::FindModuleForAddress(uptr address) {
modules_were_reloaded = true;
}
const LoadedModule *module = SearchForModule(modules_, address);
if (module) return module;
if (module)
return module;
// dlopen/dlclose interceptors invalidate the module list, but when
// interception is disabled, we need to retry if the lookup fails in
// case the module list changed.
#if !SANITIZER_INTERCEPT_DLOPEN_DLCLOSE
# if !SANITIZER_INTERCEPT_DLOPEN_DLCLOSE
if (!modules_were_reloaded) {
RefreshModules();
module = SearchForModule(modules_, address);
if (module) return module;
if (module)
return module;
}
#endif
# endif
if (fallback_modules_.size()) {
module = SearchForModule(fallback_modules_, address);
@ -260,31 +264,31 @@ class LLVMSymbolizerProcess final : public SymbolizerProcess {
// script/asan_symbolize.py and sanitizer_common.h.
void GetArgV(const char *path_to_binary,
const char *(&argv)[kArgVMax]) const override {
#if defined(__x86_64h__)
const char* const kSymbolizerArch = "--default-arch=x86_64h";
#elif defined(__x86_64__)
const char* const kSymbolizerArch = "--default-arch=x86_64";
#elif defined(__i386__)
const char* const kSymbolizerArch = "--default-arch=i386";
#elif SANITIZER_LOONGARCH64
# if defined(__x86_64h__)
const char *const kSymbolizerArch = "--default-arch=x86_64h";
# elif defined(__x86_64__)
const char *const kSymbolizerArch = "--default-arch=x86_64";
# elif defined(__i386__)
const char *const kSymbolizerArch = "--default-arch=i386";
# elif SANITIZER_LOONGARCH64
const char *const kSymbolizerArch = "--default-arch=loongarch64";
#elif SANITIZER_RISCV64
# elif SANITIZER_RISCV64
const char *const kSymbolizerArch = "--default-arch=riscv64";
#elif defined(__aarch64__)
const char* const kSymbolizerArch = "--default-arch=arm64";
#elif defined(__arm__)
const char* const kSymbolizerArch = "--default-arch=arm";
#elif defined(__powerpc64__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
const char* const kSymbolizerArch = "--default-arch=powerpc64";
#elif defined(__powerpc64__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
const char* const kSymbolizerArch = "--default-arch=powerpc64le";
#elif defined(__s390x__)
const char* const kSymbolizerArch = "--default-arch=s390x";
#elif defined(__s390__)
const char* const kSymbolizerArch = "--default-arch=s390";
#else
const char* const kSymbolizerArch = "--default-arch=unknown";
#endif
# elif defined(__aarch64__)
const char *const kSymbolizerArch = "--default-arch=arm64";
# elif defined(__arm__)
const char *const kSymbolizerArch = "--default-arch=arm";
# elif defined(__powerpc64__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
const char *const kSymbolizerArch = "--default-arch=powerpc64";
# elif defined(__powerpc64__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
const char *const kSymbolizerArch = "--default-arch=powerpc64le";
# elif defined(__s390x__)
const char *const kSymbolizerArch = "--default-arch=s390x";
# elif defined(__s390__)
const char *const kSymbolizerArch = "--default-arch=s390";
# else
const char *const kSymbolizerArch = "--default-arch=unknown";
# endif
const char *const demangle_flag =
common_flags()->demangle ? "--demangle" : "--no-demangle";
@ -315,7 +319,8 @@ static const char *ParseFileLineInfo(AddressInfo *info, const char *str) {
char *back = file_line_info + size - 1;
for (int i = 0; i < 2; ++i) {
while (back > file_line_info && IsDigit(*back)) --back;
if (*back != ':' || !IsDigit(back[1])) break;
if (*back != ':' || !IsDigit(back[1]))
break;
info->column = info->line;
info->line = internal_atoll(back + 1);
// Truncate the string at the colon to keep only filename.
@ -459,10 +464,9 @@ const char *LLVMSymbolizer::FormatAndSendCommand(const char *command_prefix,
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);
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");
@ -484,9 +488,9 @@ SymbolizerProcess::SymbolizerProcess(const char *path, bool use_posix_spawn)
CHECK_NE(path_[0], '\0');
}
static bool IsSameModule(const char* path) {
if (const char* ProcessName = GetProcessName()) {
if (const char* SymbolizerName = StripModuleName(path)) {
static bool IsSameModule(const char *path) {
if (const char *ProcessName = GetProcessName()) {
if (const char *SymbolizerName = StripModuleName(path)) {
return !internal_strcmp(ProcessName, SymbolizerName);
}
}

View file

@ -38,9 +38,10 @@
// because we do not require a C++ ABI library to be linked to a program
// using sanitizers; if it's not present, we'll just use the mangled name.
namespace __cxxabiv1 {
extern "C" SANITIZER_WEAK_ATTRIBUTE
char *__cxa_demangle(const char *mangled, char *buffer,
size_t *length, int *status);
extern "C" SANITIZER_WEAK_ATTRIBUTE char *__cxa_demangle(const char *mangled,
char *buffer,
size_t *length,
int *status);
}
namespace __sanitizer {
@ -53,8 +54,7 @@ const char *DemangleCXXABI(const char *name) {
// it does not allocate). For now, we just call it anyway, and we leak
// the returned value.
if (&__cxxabiv1::__cxa_demangle)
if (const char *demangled_name =
__cxxabiv1::__cxa_demangle(name, 0, 0, 0))
if (const char *demangled_name = __cxxabiv1::__cxa_demangle(name, 0, 0, 0))
return demangled_name;
return nullptr;
@ -85,7 +85,8 @@ const char *DemangleSwift(const char *name) {
}
const char *DemangleSwiftAndCXX(const char *name) {
if (!name) return nullptr;
if (!name)
return nullptr;
if (const char *swift_demangled_name = DemangleSwift(name))
return swift_demangled_name;
return DemangleCXXABI(name);
@ -114,7 +115,8 @@ static bool CreateTwoHighNumberedPipes(int *infd_, int *outfd_) {
} else {
outfd = sock_pair[i];
for (int j = 0; j < i; j++) {
if (sock_pair[j] == infd) continue;
if (sock_pair[j] == infd)
continue;
internal_close(sock_pair[j][0]);
internal_close(sock_pair[j][1]);
}
@ -155,7 +157,7 @@ bool SymbolizerProcess::StartSymbolizerSubprocess() {
}
if (use_posix_spawn_) {
#if SANITIZER_APPLE
# if SANITIZER_APPLE
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",
@ -165,14 +167,16 @@ bool SymbolizerProcess::StartSymbolizerSubprocess() {
input_fd_ = fd;
output_fd_ = fd;
#else // SANITIZER_APPLE
# else // SANITIZER_APPLE
UNIMPLEMENTED();
#endif // SANITIZER_APPLE
# endif // SANITIZER_APPLE
} else {
fd_t infd[2] = {}, outfd[2] = {};
if (!CreateTwoHighNumberedPipes(infd, outfd)) {
Report("WARNING: Can't create a socket pair to start "
"external symbolizer (errno: %d)\n", errno);
Report(
"WARNING: Can't create a socket pair to start "
"external symbolizer (errno: %d)\n",
errno);
return false;
}
@ -260,10 +264,11 @@ bool Addr2LineProcess::ReachedEndOfOutput(const char *buffer,
// 1. First one, corresponding to given offset to be symbolized
// (may be equal to output_terminator_, if offset is not valid).
// 2. Second one for output_terminator_, itself to mark the end of output.
if (length <= kTerminatorLen) return false;
if (length <= kTerminatorLen)
return false;
// Addr2Line output should end up with output_terminator_.
return !internal_memcmp(buffer + length - kTerminatorLen,
output_terminator_, kTerminatorLen);
return !internal_memcmp(buffer + length - kTerminatorLen, output_terminator_,
kTerminatorLen);
}
class Addr2LinePool final : public SymbolizerTool {
@ -283,9 +288,7 @@ class Addr2LinePool final : public SymbolizerTool {
return false;
}
bool SymbolizeData(uptr addr, DataInfo *info) override {
return false;
}
bool SymbolizeData(uptr addr, DataInfo *info) override { return false; }
private:
const char *SendCommand(const char *module_name, uptr module_offset) {
@ -299,22 +302,21 @@ class Addr2LinePool final : public SymbolizerTool {
}
if (!addr2line) {
addr2line =
new(*allocator_) Addr2LineProcess(addr2line_path_, module_name);
new (*allocator_) Addr2LineProcess(addr2line_path_, module_name);
addr2line_pool_.push_back(addr2line);
}
CHECK_EQ(0, internal_strcmp(module_name, addr2line->module_name()));
char buffer[kBufferSize];
internal_snprintf(buffer, kBufferSize, "0x%zx\n0x%zx\n",
module_offset, dummy_address_);
internal_snprintf(buffer, kBufferSize, "0x%zx\n0x%zx\n", module_offset,
dummy_address_);
return addr2line->SendCommand(buffer);
}
static const uptr kBufferSize = 64;
const char *addr2line_path_;
LowLevelAllocator *allocator_;
InternalMmapVector<Addr2LineProcess*> addr2line_pool_;
static const uptr dummy_address_ =
FIRST_32_SECOND_64(UINT32_MAX, UINT64_MAX);
InternalMmapVector<Addr2LineProcess *> addr2line_pool_;
static const uptr dummy_address_ = FIRST_32_SECOND_64(UINT32_MAX, UINT64_MAX);
};
# if SANITIZER_SUPPORTS_WEAK_HOOKS
@ -352,8 +354,9 @@ class InternalSymbolizer final : public SymbolizerTool {
}
bool SymbolizePC(uptr addr, SymbolizedStack *stack) override {
bool result = __sanitizer_symbolize_code(
stack->info.module, stack->info.module_offset, buffer_, sizeof(buffer_));
bool result = __sanitizer_symbolize_code(stack->info.module,
stack->info.module_offset, buffer_,
sizeof(buffer_));
if (result)
ParseSymbolizePCOutput(buffer_, stack);
return result;
@ -423,44 +426,53 @@ static SymbolizerTool *ChooseExternalSymbolizer(LowLevelAllocator *allocator) {
} else if (!internal_strncmp(binary_name, kLLVMSymbolizerPrefix,
internal_strlen(kLLVMSymbolizerPrefix))) {
VReport(2, "Using llvm-symbolizer at user-specified path: %s\n", path);
return new(*allocator) LLVMSymbolizer(path, allocator);
return new (*allocator) LLVMSymbolizer(path, allocator);
} else if (!internal_strcmp(binary_name, "atos")) {
#if SANITIZER_APPLE
# if SANITIZER_APPLE
VReport(2, "Using atos at user-specified path: %s\n", path);
return new(*allocator) AtosSymbolizer(path, allocator);
#else // SANITIZER_APPLE
return new (*allocator) AtosSymbolizer(path, allocator);
# else // SANITIZER_APPLE
Report("ERROR: Using `atos` is only supported on Darwin.\n");
Die();
#endif // SANITIZER_APPLE
# endif // SANITIZER_APPLE
} else if (!internal_strcmp(binary_name, "addr2line")) {
VReport(2, "Using addr2line at user-specified path: %s\n", path);
return new(*allocator) Addr2LinePool(path, allocator);
return new (*allocator) Addr2LinePool(path, allocator);
} else if (path) {
Report("ERROR: External symbolizer path is set to '%s' which isn't "
Report(
"ERROR: External symbolizer path is set to '%s' which isn't "
"a known symbolizer. Please set the path to the llvm-symbolizer "
"binary or other known tool.\n", path);
"binary or other known tool.\n",
path);
Die();
}
// Otherwise symbolizer program is unknown, let's search $PATH
# ifdef SANITIZER_DISABLE_SYMBOLIZER_PATH_SEARCH
VReport(2,
"Symbolizer path search is disabled in the runtime "
"build configuration.\n");
return nullptr;
# else
CHECK(path == nullptr);
#if SANITIZER_APPLE
# if SANITIZER_APPLE
if (const char *found_path = FindPathToBinary("atos")) {
VReport(2, "Using atos found at: %s\n", found_path);
return new(*allocator) AtosSymbolizer(found_path, allocator);
return new (*allocator) AtosSymbolizer(found_path, allocator);
}
#endif // SANITIZER_APPLE
# endif // SANITIZER_APPLE
if (const char *found_path = FindPathToBinary("llvm-symbolizer")) {
VReport(2, "Using llvm-symbolizer found at: %s\n", found_path);
return new(*allocator) LLVMSymbolizer(found_path, allocator);
return new (*allocator) LLVMSymbolizer(found_path, allocator);
}
if (common_flags()->allow_addr2line) {
if (const char *found_path = FindPathToBinary("addr2line")) {
VReport(2, "Using addr2line found at: %s\n", found_path);
return new(*allocator) Addr2LinePool(found_path, allocator);
return new (*allocator) Addr2LinePool(found_path, allocator);
}
}
return nullptr;
# endif // SANITIZER_DISABLE_SYMBOLIZER_PATH_SEARCH
}
static void ChooseSymbolizerTools(IntrusiveList<SymbolizerTool> *list,
@ -492,17 +504,17 @@ static void ChooseSymbolizerTools(IntrusiveList<SymbolizerTool> *list,
list->push_back(tool);
}
#if SANITIZER_APPLE
# if SANITIZER_APPLE
VReport(2, "Using dladdr symbolizer.\n");
list->push_back(new(*allocator) DlAddrSymbolizer());
#endif // SANITIZER_APPLE
list->push_back(new (*allocator) DlAddrSymbolizer());
# endif // SANITIZER_APPLE
}
Symbolizer *Symbolizer::PlatformInit() {
IntrusiveList<SymbolizerTool> list;
list.clear();
ChooseSymbolizerTools(&list, &symbolizer_allocator_);
return new(symbolizer_allocator_) Symbolizer(list);
return new (symbolizer_allocator_) Symbolizer(list);
}
void Symbolizer::LateInitialize() {

View file

@ -12,7 +12,7 @@
#include "sanitizer_platform.h"
#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \
SANITIZER_SOLARIS
SANITIZER_SOLARIS || SANITIZER_HAIKU
#include "sanitizer_common.h"
#include "sanitizer_stacktrace.h"
@ -91,38 +91,6 @@ _Unwind_Reason_Code Unwind_Trace(struct _Unwind_Context *ctx, void *param) {
} // namespace
#if SANITIZER_ANDROID
void SanitizerInitializeUnwinder() {
if (AndroidGetApiLevel() >= ANDROID_LOLLIPOP_MR1) return;
// Pre-lollipop Android can not unwind through signal handler frames with
// libgcc unwinder, but it has a libcorkscrew.so library with the necessary
// workarounds.
void *p = dlopen("libcorkscrew.so", RTLD_LAZY);
if (!p) {
VReport(1,
"Failed to open libcorkscrew.so. You may see broken stack traces "
"in SEGV reports.");
return;
}
acquire_my_map_info_list =
(acquire_my_map_info_list_func)(uptr)dlsym(p, "acquire_my_map_info_list");
release_my_map_info_list =
(release_my_map_info_list_func)(uptr)dlsym(p, "release_my_map_info_list");
unwind_backtrace_signal_arch = (unwind_backtrace_signal_arch_func)(uptr)dlsym(
p, "unwind_backtrace_signal_arch");
if (!acquire_my_map_info_list || !release_my_map_info_list ||
!unwind_backtrace_signal_arch) {
VReport(1,
"Failed to find one of the required symbols in libcorkscrew.so. "
"You may see broken stack traces in SEGV reports.");
acquire_my_map_info_list = 0;
unwind_backtrace_signal_arch = 0;
release_my_map_info_list = 0;
}
}
#endif
void BufferedStackTrace::UnwindSlow(uptr pc, u32 max_depth) {
CHECK_GE(max_depth, 2);
size = 0;
@ -171,4 +139,4 @@ void BufferedStackTrace::UnwindSlow(uptr pc, void *context, u32 max_depth) {
} // namespace __sanitizer
#endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD ||
// SANITIZER_SOLARIS
// SANITIZER_SOLARIS || SANITIZER_HAIKU

View file

@ -75,6 +75,11 @@ void BufferedStackTrace::UnwindSlow(uptr pc, void *context, u32 max_depth) {
stack_frame.AddrPC.Offset = ctx.Pc;
stack_frame.AddrFrame.Offset = ctx.R11;
stack_frame.AddrStack.Offset = ctx.Sp;
# elif SANITIZER_MIPS32
int machine_type = IMAGE_FILE_MACHINE_R4000;
stack_frame.AddrPC.Offset = ctx.Fir;
stack_frame.AddrFrame.Offset = ctx.IntS8;
stack_frame.AddrStack.Offset = ctx.IntSp;
# else
int machine_type = IMAGE_FILE_MACHINE_I386;
stack_frame.AddrPC.Offset = ctx.Eip;

View file

@ -1011,6 +1011,9 @@ void SignalContext::InitPcSpBp() {
# if SANITIZER_ARM
bp = (uptr)context_record->R11;
sp = (uptr)context_record->Sp;
# elif SANITIZER_MIPS32
bp = (uptr)context_record->IntS8;
sp = (uptr)context_record->IntSp;
# else
bp = (uptr)context_record->Ebp;
sp = (uptr)context_record->Esp;

View file

@ -12,6 +12,9 @@
// sanitizer_common/sanitizer_common_interceptors.inc
//===----------------------------------------------------------------------===//
#include <stdarg.h>
#include "interception/interception.h"
#include "sanitizer_common/sanitizer_allocator_dlsym.h"
#include "sanitizer_common/sanitizer_atomic.h"
#include "sanitizer_common/sanitizer_errno.h"
@ -19,21 +22,20 @@
#include "sanitizer_common/sanitizer_internal_defs.h"
#include "sanitizer_common/sanitizer_libc.h"
#include "sanitizer_common/sanitizer_linux.h"
#include "sanitizer_common/sanitizer_platform_interceptors.h"
#include "sanitizer_common/sanitizer_platform_limits_netbsd.h"
#include "sanitizer_common/sanitizer_platform_limits_posix.h"
#include "sanitizer_common/sanitizer_posix.h"
#include "sanitizer_common/sanitizer_stacktrace.h"
#include "sanitizer_common/sanitizer_tls_get_addr.h"
#include "interception/interception.h"
#include "sanitizer_common/sanitizer_vector.h"
#include "tsan_fd.h"
#include "tsan_interceptors.h"
#include "tsan_interface.h"
#include "tsan_platform.h"
#include "tsan_suppressions.h"
#include "tsan_rtl.h"
#include "tsan_mman.h"
#include "tsan_fd.h"
#include <stdarg.h>
#include "tsan_platform.h"
#include "tsan_rtl.h"
#include "tsan_suppressions.h"
using namespace __tsan;
@ -177,7 +179,7 @@ struct ThreadSignalContext {
SignalDesc pending_signals[kSigCount];
// emptyset and oldset are too big for stack.
__sanitizer_sigset_t emptyset;
__sanitizer_sigset_t oldset;
__sanitizer::Vector<__sanitizer_sigset_t> oldset;
};
void EnterBlockingFunc(ThreadState *thr) {
@ -558,6 +560,7 @@ static void SetJmp(ThreadState *thr, uptr sp) {
buf->shadow_stack_pos = thr->shadow_stack_pos;
ThreadSignalContext *sctx = SigCtx(thr);
buf->int_signal_send = sctx ? sctx->int_signal_send : 0;
buf->oldset_stack_size = sctx ? sctx->oldset.Size() : 0;
buf->in_blocking_func = atomic_load(&thr->in_blocking_func, memory_order_relaxed);
buf->in_signal_handler = atomic_load(&thr->in_signal_handler,
memory_order_relaxed);
@ -574,8 +577,11 @@ static void LongJmp(ThreadState *thr, uptr *env) {
while (thr->shadow_stack_pos > buf->shadow_stack_pos)
FuncExit(thr);
ThreadSignalContext *sctx = SigCtx(thr);
if (sctx)
if (sctx) {
sctx->int_signal_send = buf->int_signal_send;
while (sctx->oldset.Size() > buf->oldset_stack_size)
sctx->oldset.PopBack();
}
atomic_store(&thr->in_blocking_func, buf->in_blocking_func,
memory_order_relaxed);
atomic_store(&thr->in_signal_handler, buf->in_signal_handler,
@ -742,6 +748,41 @@ TSAN_INTERCEPTOR(void, free, void *p) {
user_free(thr, pc, p);
}
# if SANITIZER_INTERCEPT_FREE_SIZED
TSAN_INTERCEPTOR(void, free_sized, void *p, uptr size) {
if (UNLIKELY(!p))
return;
if (in_symbolizer())
return InternalFree(p);
if (DlsymAlloc::PointerIsMine(p))
return DlsymAlloc::Free(p);
invoke_free_hook(p);
SCOPED_INTERCEPTOR_RAW(free_sized, p, size);
user_free(thr, pc, p);
}
# define TSAN_MAYBE_INTERCEPT_FREE_SIZED INTERCEPT_FUNCTION(free_sized)
# else
# define TSAN_MAYBE_INTERCEPT_FREE_SIZED
# endif
# if SANITIZER_INTERCEPT_FREE_ALIGNED_SIZED
TSAN_INTERCEPTOR(void, free_aligned_sized, void *p, uptr alignment, uptr size) {
if (UNLIKELY(!p))
return;
if (in_symbolizer())
return InternalFree(p);
if (DlsymAlloc::PointerIsMine(p))
return DlsymAlloc::Free(p);
invoke_free_hook(p);
SCOPED_INTERCEPTOR_RAW(free_aligned_sized, p, alignment, size);
user_free(thr, pc, p);
}
# define TSAN_MAYBE_INTERCEPT_FREE_ALIGNED_SIZED \
INTERCEPT_FUNCTION(free_aligned_sized)
# else
# define TSAN_MAYBE_INTERCEPT_FREE_ALIGNED_SIZED
# endif
TSAN_INTERCEPTOR(void, cfree, void *p) {
if (UNLIKELY(!p))
return;
@ -758,6 +799,9 @@ TSAN_INTERCEPTOR(uptr, malloc_usable_size, void *p) {
SCOPED_INTERCEPTOR_RAW(malloc_usable_size, p);
return user_alloc_usable_size(p);
}
#else
# define TSAN_MAYBE_INTERCEPT_FREE_SIZED
# define TSAN_MAYBE_INTERCEPT_FREE_ALIGNED_SIZED
#endif
TSAN_INTERCEPTOR(char *, strcpy, char *dst, const char *src) {
@ -892,10 +936,9 @@ constexpr u32 kGuardWaiter = 1 << 17;
static int guard_acquire(ThreadState *thr, uptr pc, atomic_uint32_t *g,
bool blocking_hooks = true) {
if (blocking_hooks)
OnPotentiallyBlockingRegionBegin();
auto on_exit = at_scope_exit([blocking_hooks] {
if (blocking_hooks)
bool in_potentially_blocking_region = false;
auto on_exit = at_scope_exit([&] {
if (in_potentially_blocking_region)
OnPotentiallyBlockingRegionEnd();
});
@ -912,10 +955,15 @@ static int guard_acquire(ThreadState *thr, uptr pc, atomic_uint32_t *g,
} else {
if ((cmp & kGuardWaiter) ||
atomic_compare_exchange_strong(g, &cmp, cmp | kGuardWaiter,
memory_order_relaxed))
memory_order_relaxed)) {
if (blocking_hooks && !in_potentially_blocking_region) {
in_potentially_blocking_region = true;
OnPotentiallyBlockingRegionBegin();
}
FutexWait(g, cmp | kGuardWaiter);
}
}
}
}
static void guard_release(ThreadState *thr, uptr pc, atomic_uint32_t *g,
@ -976,6 +1024,7 @@ void PlatformCleanUpThreadState(ThreadState *thr) {
&thr->signal_ctx, memory_order_relaxed);
if (sctx) {
atomic_store(&thr->signal_ctx, 0, memory_order_relaxed);
sctx->oldset.Reset();
UnmapOrDie(sctx, sizeof(*sctx));
}
}
@ -2172,7 +2221,8 @@ void ProcessPendingSignalsImpl(ThreadState *thr) {
return;
atomic_fetch_add(&thr->in_signal_handler, 1, memory_order_relaxed);
internal_sigfillset(&sctx->emptyset);
int res = REAL(pthread_sigmask)(SIG_SETMASK, &sctx->emptyset, &sctx->oldset);
__sanitizer_sigset_t *oldset = sctx->oldset.PushBack();
int res = REAL(pthread_sigmask)(SIG_SETMASK, &sctx->emptyset, oldset);
CHECK_EQ(res, 0);
for (int sig = 0; sig < kSigCount; sig++) {
SignalDesc *signal = &sctx->pending_signals[sig];
@ -2182,8 +2232,9 @@ void ProcessPendingSignalsImpl(ThreadState *thr) {
&signal->ctx);
}
}
res = REAL(pthread_sigmask)(SIG_SETMASK, &sctx->oldset, 0);
res = REAL(pthread_sigmask)(SIG_SETMASK, oldset, 0);
CHECK_EQ(res, 0);
sctx->oldset.PopBack();
atomic_fetch_add(&thr->in_signal_handler, -1, memory_order_relaxed);
}
@ -2951,6 +3002,8 @@ void InitializeInterceptors() {
TSAN_INTERCEPT(realloc);
TSAN_INTERCEPT(reallocarray);
TSAN_INTERCEPT(free);
TSAN_MAYBE_INTERCEPT_FREE_SIZED;
TSAN_MAYBE_INTERCEPT_FREE_ALIGNED_SIZED;
TSAN_INTERCEPT(cfree);
TSAN_INTERCEPT(munmap);
TSAN_MAYBE_INTERCEPT_MEMALIGN;
@ -3073,6 +3126,10 @@ void InitializeInterceptors() {
#if !SANITIZER_ANDROID
TSAN_INTERCEPT(dl_iterate_phdr);
#endif
// Symbolization indirectly calls dl_iterate_phdr
ready_to_symbolize = true;
TSAN_MAYBE_INTERCEPT_ON_EXIT;
TSAN_INTERCEPT(__cxa_atexit);
TSAN_INTERCEPT(_exit);

View file

@ -122,7 +122,6 @@ void __tsan_java_move(jptr src, jptr dst, jptr size) {
DCHECK_GE(dst, jctx->heap_begin);
DCHECK_LE(dst + size, jctx->heap_begin + jctx->heap_size);
DCHECK_NE(dst, src);
DCHECK_NE(size, 0);
// Assuming it's not running concurrently with threads that do
// memory accesses and mutex operations (stop-the-world phase).

View file

@ -73,15 +73,19 @@ using namespace __tsan;
invoke_free_hook(ptr); \
SCOPED_INTERCEPTOR_RAW(free, ptr); \
user_free(thr, pc, ptr)
#define COMMON_MALLOC_SIZE(ptr) uptr size = user_alloc_usable_size(ptr);
#define COMMON_MALLOC_FILL_STATS(zone, stats)
#define COMMON_MALLOC_REPORT_UNKNOWN_REALLOC(ptr, zone_ptr, zone_name) \
# define COMMON_MALLOC_FREE_SIZED(ptr, size) COMMON_MALLOC_FREE(ptr)
# define COMMON_MALLOC_FREE_ALIGNED_SIZED(ptr, alignment, size) \
COMMON_MALLOC_FREE(ptr)
# define COMMON_MALLOC_SIZE(ptr) uptr size = user_alloc_usable_size(ptr);
# define COMMON_MALLOC_FILL_STATS(zone, stats)
# define COMMON_MALLOC_REPORT_UNKNOWN_REALLOC(ptr, zone_ptr, zone_name) \
(void)zone_name; \
Report("mz_realloc(%p) -- attempting to realloc unallocated memory.\n", ptr);
#define COMMON_MALLOC_NAMESPACE __tsan
#define COMMON_MALLOC_HAS_ZONE_ENUMERATOR 0
#define COMMON_MALLOC_HAS_EXTRA_INTROSPECTION_INIT 0
Report("mz_realloc(%p) -- attempting to realloc unallocated memory.\n", \
ptr);
# define COMMON_MALLOC_NAMESPACE __tsan
# define COMMON_MALLOC_HAS_ZONE_ENUMERATOR 0
# define COMMON_MALLOC_HAS_EXTRA_INTROSPECTION_INIT 0
#include "sanitizer_common/sanitizer_malloc_mac.inc"
# include "sanitizer_common/sanitizer_malloc_mac.inc"
#endif

View file

@ -681,6 +681,33 @@ struct MappingGoMips64_47 {
static const uptr kShadowAdd = 0x200000000000ull;
};
/* Go on linux/riscv64 (48-bit VMA)
0000 0001 0000 - 00e0 0000 0000: executable and heap (896 GiB)
00e0 0000 0000 - 2000 0000 0000: -
2000 0000 0000 - 2400 0000 0000: shadow - 4 TiB ( ~ 4 * app)
2400 0000 0000 - 3000 0000 0000: -
3000 0000 0000 - 3100 0000 0000: metainfo - 1 TiB ( ~ 1 * app)
3100 0000 0000 - 8000 0000 0000: -
*/
struct MappingGoRiscv64 {
static const uptr kMetaShadowBeg = 0x300000000000ull;
static const uptr kMetaShadowEnd = 0x310000000000ull;
static const uptr kShadowBeg = 0x200000000000ull;
static const uptr kShadowEnd = 0x240000000000ull;
static const uptr kLoAppMemBeg = 0x000000010000ull;
static const uptr kLoAppMemEnd = 0x000e00000000ull;
static const uptr kMidAppMemBeg = 0;
static const uptr kMidAppMemEnd = 0;
static const uptr kHiAppMemBeg = 0;
static const uptr kHiAppMemEnd = 0;
static const uptr kHeapMemBeg = 0;
static const uptr kHeapMemEnd = 0;
static const uptr kVdsoBeg = 0;
static const uptr kShadowMsk = 0;
static const uptr kShadowXor = 0;
static const uptr kShadowAdd = 0x200000000000ull;
};
/*
Go on linux/s390x
0000 0000 1000 - 1000 0000 0000: executable and heap - 16 TiB
@ -728,6 +755,8 @@ ALWAYS_INLINE auto SelectMapping(Arg arg) {
return Func::template Apply<MappingGoAarch64>(arg);
# elif defined(__loongarch_lp64)
return Func::template Apply<MappingGoLoongArch64_47>(arg);
# elif SANITIZER_RISCV64
return Func::template Apply<MappingGoRiscv64>(arg);
# elif SANITIZER_WINDOWS
return Func::template Apply<MappingGoWindows>(arg);
# else
@ -798,6 +827,7 @@ void ForEachMapping() {
Func::template Apply<MappingGoAarch64>();
Func::template Apply<MappingGoLoongArch64_47>();
Func::template Apply<MappingGoMips64_47>();
Func::template Apply<MappingGoRiscv64>();
Func::template Apply<MappingGoS390x>();
}
@ -901,7 +931,7 @@ bool IsAppMem(uptr mem) { return SelectMapping<IsAppMemImpl>(mem); }
struct IsShadowMemImpl {
template <typename Mapping>
static bool Apply(uptr mem) {
return mem >= Mapping::kShadowBeg && mem <= Mapping::kShadowEnd;
return mem >= Mapping::kShadowBeg && mem < Mapping::kShadowEnd;
}
};
@ -913,7 +943,7 @@ bool IsShadowMem(RawShadow *p) {
struct IsMetaMemImpl {
template <typename Mapping>
static bool Apply(uptr mem) {
return mem >= Mapping::kMetaShadowBeg && mem <= Mapping::kMetaShadowEnd;
return mem >= Mapping::kMetaShadowBeg && mem < Mapping::kMetaShadowEnd;
}
};

View file

@ -259,7 +259,15 @@ static void ReExecIfNeeded(bool ignore_heap) {
"WARNING: Program is run with randomized virtual address "
"space, which wouldn't work with ThreadSanitizer on Android.\n"
"Re-execing with fixed virtual address space.\n");
CHECK_NE(personality(old_personality | ADDR_NO_RANDOMIZE), -1);
if (personality(old_personality | ADDR_NO_RANDOMIZE) == -1) {
Printf(
"FATAL: ThreadSanitizer: unable to disable ASLR (perhaps "
"sandboxing is enabled?).\n");
Printf("FATAL: Please rerun without sandboxing and/or ASLR.\n");
Die();
}
reexec = true;
}
# endif
@ -287,7 +295,18 @@ static void ReExecIfNeeded(bool ignore_heap) {
"possibly due to high-entropy ASLR.\n"
"Re-execing with fixed virtual address space.\n"
"N.B. reducing ASLR entropy is preferable.\n");
CHECK_NE(personality(old_personality | ADDR_NO_RANDOMIZE), -1);
if (personality(old_personality | ADDR_NO_RANDOMIZE) == -1) {
Printf(
"FATAL: ThreadSanitizer: encountered an incompatible memory "
"layout but was unable to disable ASLR (perhaps sandboxing is "
"enabled?).\n");
Printf(
"FATAL: Please rerun with lower ASLR entropy, ASLR disabled, "
"and/or sandboxing disabled.\n");
Die();
}
reexec = true;
} else {
Printf(
@ -373,6 +392,12 @@ void InitializePlatformEarly() {
Printf("FATAL: Found %zd - Supported 39 and 48\n", vmaSize);
Die();
}
# else
if (vmaSize != 48) {
Printf("FATAL: ThreadSanitizer: unsupported VMA range\n");
Printf("FATAL: Found %zd - Supported 48\n", vmaSize);
Die();
}
# endif
# endif

View file

@ -566,17 +566,32 @@ static bool IsValidMmapRange(uptr addr, uptr size) {
return false;
}
void UnmapShadow(ThreadState *thr, uptr addr, uptr size) {
void UnmapShadow(ThreadState* thr, uptr addr, uptr size) {
if (size == 0 || !IsValidMmapRange(addr, size))
return;
DontNeedShadowFor(addr, size);
// unmap shadow is related to semantic of mmap/munmap, so we
// should clear the whole shadow range, including the tail shadow
// while addr + size % kShadowCell != 0.
uptr rounded_size_shadow = RoundUp(addr + size, kShadowCell) - addr;
DontNeedShadowFor(addr, rounded_size_shadow);
ScopedGlobalProcessor sgp;
SlotLocker locker(thr, true);
ctx->metamap.ResetRange(thr->proc(), addr, size, true);
uptr rounded_size_meta = RoundUp(addr + size, kMetaShadowCell) - addr;
ctx->metamap.ResetRange(thr->proc(), addr, rounded_size_meta, true);
}
#endif
void MapShadow(uptr addr, uptr size) {
// Although named MapShadow, this function's semantic is unrelated to
// UnmapShadow. This function currently only used for Go's lazy allocation
// of shadow, whose targets are program section (e.g., bss, data, etc.).
// Therefore, we can guarantee that the addr and size align to kShadowCell
// and kMetaShadowCell by the following assertions.
DCHECK_EQ(addr % kShadowCell, 0);
DCHECK_EQ(size % kShadowCell, 0);
DCHECK_EQ(addr % kMetaShadowCell, 0);
DCHECK_EQ(size % kMetaShadowCell, 0);
// Ensure thead registry lock held, so as to synchronize
// with DoReset, which also access the mapped_shadow_* ctxt fields.
ThreadRegistryLock lock0(&ctx->thread_registry);
@ -624,6 +639,7 @@ void MapShadow(uptr addr, uptr size) {
static uptr mapped_meta_end = 0;
uptr meta_begin = (uptr)MemToMeta(addr);
uptr meta_end = (uptr)MemToMeta(addr + size);
// Windows wants 64K alignment.
meta_begin = RoundDownTo(meta_begin, 64 << 10);
meta_end = RoundUpTo(meta_end, 64 << 10);
if (!data_mapped) {
@ -634,9 +650,6 @@ void MapShadow(uptr addr, uptr size) {
Die();
} else {
// Mapping continuous heap.
// Windows wants 64K alignment.
meta_begin = RoundDownTo(meta_begin, 64 << 10);
meta_end = RoundUpTo(meta_end, 64 << 10);
CHECK_GT(meta_end, mapped_meta_end);
if (meta_begin < mapped_meta_end)
meta_begin = mapped_meta_end;
@ -679,6 +692,12 @@ void CheckUnwind() {
bool is_initialized;
// Symbolization indirectly calls dl_iterate_phdr. If a CHECK() fails early on
// (prior to the dl_iterate_phdr interceptor setup), resulting in an attempted
// symbolization, it will segfault.
// dl_iterate_phdr is not intercepted for Android.
bool ready_to_symbolize = SANITIZER_ANDROID;
void Initialize(ThreadState *thr) {
// Thread safe because done before all threads exist.
if (is_initialized)

View file

@ -54,13 +54,15 @@
namespace __tsan {
extern bool ready_to_symbolize;
#if !SANITIZER_GO
struct MapUnmapCallback;
# if defined(__mips64) || defined(__aarch64__) || defined(__loongarch__) || \
defined(__powerpc__) || SANITIZER_RISCV64
struct AP32 {
static const uptr kSpaceBeg = 0;
static const uptr kSpaceBeg = SANITIZER_MMAP_BEGIN;
static const u64 kSpaceSize = SANITIZER_MMAP_RANGE_SIZE;
static const uptr kMetadataSize = 0;
typedef __sanitizer::CompactSizeClassMap SizeClassMap;
@ -98,6 +100,7 @@ struct JmpBuf {
uptr sp;
int int_signal_send;
bool in_blocking_func;
uptr oldset_stack_size;
uptr in_signal_handler;
uptr *shadow_stack_pos;
};

View file

@ -523,9 +523,9 @@ SECOND:
}
void ShadowSet(RawShadow* p, RawShadow* end, RawShadow v) {
DCHECK_LE(p, end);
DCHECK_LT(p, end);
DCHECK(IsShadowMem(p));
DCHECK(IsShadowMem(end));
DCHECK(IsShadowMem(end - 1));
UNUSED const uptr kAlign = kShadowCnt * kShadowSize;
DCHECK_EQ(reinterpret_cast<uptr>(p) % kAlign, 0);
DCHECK_EQ(reinterpret_cast<uptr>(end) % kAlign, 0);
@ -569,6 +569,7 @@ static void MemoryRangeSet(uptr addr, uptr size, RawShadow val) {
RawShadow* mid1 =
Min(end, reinterpret_cast<RawShadow*>(RoundUp(
reinterpret_cast<uptr>(begin) + kPageSize / 2, kPageSize)));
// begin must < mid1
ShadowSet(begin, mid1, val);
// Reset middle part.
RawShadow* mid2 = RoundDown(end, kPageSize);
@ -577,7 +578,10 @@ static void MemoryRangeSet(uptr addr, uptr size, RawShadow val) {
Die();
}
// Set the ending.
if (mid2 < end)
ShadowSet(mid2, end, val);
else
DCHECK_EQ(mid2, end);
}
void MemoryResetRange(ThreadState* thr, uptr pc, uptr addr, uptr size) {
@ -669,7 +673,7 @@ void MemoryAccessRangeT(ThreadState* thr, uptr pc, uptr addr, uptr size) {
RawShadow* shadow_mem = MemToShadow(addr);
DPrintf2("#%d: MemoryAccessRange: @%p %p size=%d is_read=%d\n", thr->tid,
(void*)pc, (void*)addr, (int)size, is_read);
DCHECK_NE(size, 0);
#if SANITIZER_DEBUG
if (!IsAppMem(addr)) {
Printf("Access to non app mem start: %p\n", (void*)addr);
@ -684,16 +688,18 @@ void MemoryAccessRangeT(ThreadState* thr, uptr pc, uptr addr, uptr size) {
DCHECK(IsShadowMem(shadow_mem));
}
RawShadow* shadow_mem_end = reinterpret_cast<RawShadow*>(
reinterpret_cast<uptr>(shadow_mem) + size * kShadowMultiplier - 1);
if (!IsShadowMem(shadow_mem_end)) {
Printf("Bad shadow end addr: %p (%p)\n", shadow_mem_end,
uptr rounded_size =
(RoundUpTo(addr + size, kShadowCell) - RoundDownTo(addr, kShadowCell));
RawShadow* shadow_mem_end =
shadow_mem + rounded_size / kShadowCell * kShadowCnt;
if (!IsShadowMem(shadow_mem_end - 1)) {
Printf("Bad shadow end addr: %p (%p)\n", shadow_mem_end - 1,
(void*)(addr + size - 1));
Printf(
"Shadow start addr (ok): %p (%p); size: 0x%zx; kShadowMultiplier: "
"%zx\n",
shadow_mem, (void*)addr, size, kShadowMultiplier);
DCHECK(IsShadowMem(shadow_mem_end));
"Shadow start addr (ok): %p (%p); size: 0x%zx; rounded_size: 0x%zx; "
"kShadowMultiplier: %zx\n",
shadow_mem, (void*)addr, size, rounded_size, kShadowMultiplier);
DCHECK(IsShadowMem(shadow_mem_end - 1));
}
#endif

View file

@ -846,7 +846,16 @@ ALWAYS_INLINE USED void PrintCurrentStack(uptr pc, bool fast) {
ptrace->trace_buffer[i] = ptrace->trace_buffer[ptrace->size - i - 1];
ptrace->trace_buffer[ptrace->size - i - 1] = tmp;
}
if (ready_to_symbolize) {
PrintStack(SymbolizeStack(*ptrace));
} else {
Printf(
"WARNING: PrintCurrentStack() has been called too early, before "
"symbolization is possible. Printing unsymbolized stack trace:\n");
for (unsigned int i = 0; i < ptrace->size; i++)
Printf(" #%u: 0x%zx\n", i, ptrace->trace[i]);
}
#endif
}

View file

@ -246,12 +246,29 @@ void MetaMap::MoveMemory(uptr src, uptr dst, uptr sz) {
// there are no concurrent accesses to the regions (e.g. stop-the-world).
CHECK_NE(src, dst);
CHECK_NE(sz, 0);
// The current MoveMemory implementation behaves incorrectly when src, dst,
// and sz are not aligned to kMetaShadowCell.
// For example, with kMetaShadowCell == 8:
// - src = 4: unexpectedly clears the metadata for the range [0, 4).
// - src = 16, dst = 4, size = 8: A sync variable for addr = 20, which should
// be moved to the metadata for address 8, is incorrectly moved to the
// metadata for address 0 instead.
// - src = 0, sz = 4: fails to move the tail metadata.
// Therefore, the following assertions is needed.
DCHECK_EQ(src % kMetaShadowCell, 0);
DCHECK_EQ(dst % kMetaShadowCell, 0);
DCHECK_EQ(sz % kMetaShadowCell, 0);
uptr diff = dst - src;
u32 *src_meta = MemToMeta(src);
u32 *dst_meta = MemToMeta(dst);
u32 *src_meta_end = MemToMeta(src + sz);
uptr inc = 1;
if (dst > src) {
u32 *src_meta, *dst_meta, *src_meta_end;
uptr inc;
if (dst < src) {
src_meta = MemToMeta(src);
dst_meta = MemToMeta(dst);
src_meta_end = MemToMeta(src + sz);
inc = 1;
} else {
src_meta = MemToMeta(src + sz) - 1;
dst_meta = MemToMeta(dst + sz) - 1;
src_meta_end = MemToMeta(src) - 1;

View file

@ -16,7 +16,7 @@
#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || \
defined(__NetBSD__) || defined(__DragonFly__) || \
(defined(__sun__) && defined(__svr4__)) || defined(_WIN32) || \
defined(__Fuchsia__)
defined(__Fuchsia__) || defined(__HAIKU__)
#define CAN_SANITIZE_UB 1
#else
# define CAN_SANITIZE_UB 0

View file

@ -403,6 +403,7 @@ const sanitizer_common_sources = [_][]const u8{
"sanitizer_flag_parser.cpp",
"sanitizer_flags.cpp",
"sanitizer_fuchsia.cpp",
"sanitizer_haiku.cpp",
"sanitizer_libc.cpp",
"sanitizer_libignore.cpp",
"sanitizer_linux.cpp",
@ -420,6 +421,7 @@ const sanitizer_common_sources = [_][]const u8{
"sanitizer_procmaps_bsd.cpp",
"sanitizer_procmaps_common.cpp",
"sanitizer_procmaps_fuchsia.cpp",
"sanitizer_procmaps_haiku.cpp",
"sanitizer_procmaps_linux.cpp",
"sanitizer_procmaps_mac.cpp",
"sanitizer_procmaps_solaris.cpp",
@ -478,6 +480,7 @@ const sanitizer_symbolizer_sources = [_][]const u8{
};
const interception_sources = [_][]const u8{
"interception_aix.cpp",
"interception_linux.cpp",
"interception_mac.cpp",
"interception_win.cpp",