From: Martin Liska Date: Tue, 5 Nov 2019 13:54:57 +0000 (+0100) Subject: Libsanitizer: merge from trunk with merge.sh. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=3ca75cd55030a53a858bdbe9aba6d87f6b1e90b8;p=gcc.git Libsanitizer: merge from trunk with merge.sh. 2019-11-05 Martin Liska * all source files: Merge from upstream r375507. From-SVN: r277834 --- diff --git a/libsanitizer/ChangeLog b/libsanitizer/ChangeLog index 2724f2829b3..3a926394b73 100644 --- a/libsanitizer/ChangeLog +++ b/libsanitizer/ChangeLog @@ -1,3 +1,7 @@ +2019-11-05 Martin Liska + + * all source files: Merge from upstream r375507. + 2019-10-22 Tamar Christina PR sanitizer/92154 diff --git a/libsanitizer/MERGE b/libsanitizer/MERGE index bb1b045f488..b7bf2529910 100644 --- a/libsanitizer/MERGE +++ b/libsanitizer/MERGE @@ -1,4 +1,4 @@ -368656 +375507 The first line of this file holds the svn revision number of the last merge done from the master library sources. diff --git a/libsanitizer/asan/asan_allocator.cpp b/libsanitizer/asan/asan_allocator.cpp index b58116e17b7..c9e9f5a93d0 100644 --- a/libsanitizer/asan/asan_allocator.cpp +++ b/libsanitizer/asan/asan_allocator.cpp @@ -1075,7 +1075,7 @@ IgnoreObjectResult IgnoreObjectLocked(const void *p) { } // namespace __lsan // ---------------------- Interface ---------------- {{{1 -using namespace __asan; // NOLINT +using namespace __asan; // ASan allocator doesn't reserve extra bytes, so normally we would // just return "size". We don't want to expose our redzone sizes, etc here. diff --git a/libsanitizer/asan/asan_debugging.cpp b/libsanitizer/asan/asan_debugging.cpp index 3fc15adf7b8..c01360b52fc 100644 --- a/libsanitizer/asan/asan_debugging.cpp +++ b/libsanitizer/asan/asan_debugging.cpp @@ -25,7 +25,7 @@ using namespace __asan; static void FindInfoForStackVar(uptr addr, const char *frame_descr, uptr offset, char *name, uptr name_size, - uptr ®ion_address, uptr ®ion_size) { + uptr *region_address, uptr *region_size) { InternalMmapVector vars; vars.reserve(16); if (!ParseFrameDescription(frame_descr, &vars)) { @@ -39,8 +39,8 @@ static void FindInfoForStackVar(uptr addr, const char *frame_descr, uptr offset, // the whole name and then terminate with '\0'. internal_strlcpy(name, vars[i].name_pos, Min(name_size, vars[i].name_len + 1)); - region_address = addr - (offset - vars[i].beg); - region_size = vars[i].size; + *region_address = addr - (offset - vars[i].beg); + *region_size = vars[i].size; return; } } @@ -108,7 +108,7 @@ const char *__asan_locate_address(uptr addr, char *name, uptr name_size, // region_{address,size} are already 0 } else { FindInfoForStackVar(addr, stack->frame_descr, stack->offset, name, - name_size, region_address, region_size); + name_size, ®ion_address, ®ion_size); } } else if (auto global = descr.AsGlobal()) { region_kind = "global"; diff --git a/libsanitizer/asan/asan_descriptions.h b/libsanitizer/asan/asan_descriptions.h index 28b38100b85..ee0e2061559 100644 --- a/libsanitizer/asan/asan_descriptions.h +++ b/libsanitizer/asan/asan_descriptions.h @@ -203,7 +203,7 @@ class AddressDescription { AddressDescription() = default; // shouldLockThreadRegistry allows us to skip locking if we're sure we already // have done it. - AddressDescription(uptr addr, bool shouldLockThreadRegistry = true) + explicit AddressDescription(uptr addr, bool shouldLockThreadRegistry = true) : AddressDescription(addr, 1, shouldLockThreadRegistry) {} AddressDescription(uptr addr, uptr access_size, bool shouldLockThreadRegistry = true); diff --git a/libsanitizer/asan/asan_errors.cpp b/libsanitizer/asan/asan_errors.cpp index 75ee996ceef..541c6e0353b 100644 --- a/libsanitizer/asan/asan_errors.cpp +++ b/libsanitizer/asan/asan_errors.cpp @@ -35,7 +35,8 @@ static void OnStackUnwind(const SignalContext &sig, // corresponding code in the sanitizer_common and we use this callback to // print it. static_cast(callback_context)->Print(); - stack->Unwind(sig.pc, sig.bp, sig.context, fast); + stack->Unwind(StackTrace::GetNextInstructionPc(sig.pc), sig.bp, sig.context, + fast); } void ErrorDeadlySignal::Print() { @@ -244,7 +245,7 @@ void ErrorInvalidPosixMemalignAlignment::Print() { "ERROR: AddressSanitizer: invalid alignment requested in posix_memalign: " "%zd, alignment must be a power of two and a multiple of sizeof(void*) " "== %zd (thread %s)\n", - alignment, sizeof(void*), AsanThreadIdAndName(tid).c_str()); // NOLINT + alignment, sizeof(void *), AsanThreadIdAndName(tid).c_str()); Printf("%s", d.Default()); stack->Print(); PrintHintAllocatorCannotReturnNull(); diff --git a/libsanitizer/asan/asan_errors.h b/libsanitizer/asan/asan_errors.h index b84f56c1853..a7fda2fd9f5 100644 --- a/libsanitizer/asan/asan_errors.h +++ b/libsanitizer/asan/asan_errors.h @@ -48,7 +48,8 @@ struct ErrorDeadlySignal : ErrorBase { scariness.Scare(10, "stack-overflow"); } else if (!signal.is_memory_access) { scariness.Scare(10, "signal"); - } else if (signal.addr < GetPageSizeCached()) { + } else if (signal.is_true_faulting_addr && + signal.addr < GetPageSizeCached()) { scariness.Scare(10, "null-deref"); } else if (signal.addr == signal.pc) { scariness.Scare(60, "wild-jump"); diff --git a/libsanitizer/asan/asan_flags.inc b/libsanitizer/asan/asan_flags.inc index d360e03ca55..43c70dbca56 100644 --- a/libsanitizer/asan/asan_flags.inc +++ b/libsanitizer/asan/asan_flags.inc @@ -139,10 +139,10 @@ ASAN_FLAG( "If >= 2, detect operations like <, <=, >, >= and - on invalid pointer " "pairs (e.g. when pointers belong to different objects); " "If == 1, detect invalid operations only when both pointers are non-null.") -ASAN_FLAG( - bool, detect_container_overflow, true, - "If true, honor the container overflow annotations. See " - "https://github.com/google/sanitizers/wiki/AddressSanitizerContainerOverflow") +ASAN_FLAG(bool, detect_container_overflow, true, + "If true, honor the container overflow annotations. See " + "https://github.com/google/sanitizers/wiki/" + "AddressSanitizerContainerOverflow") ASAN_FLAG(int, detect_odr_violation, 2, "If >=2, detect violation of One-Definition-Rule (ODR); " "If ==1, detect ODR-violation only if the two variables " @@ -158,5 +158,6 @@ ASAN_FLAG(bool, allocator_frees_and_returns_null_on_realloc_zero, true, ASAN_FLAG(bool, verify_asan_link_order, true, "Check position of ASan runtime in library list (needs to be disabled" " when other library has to be preloaded system-wide)") -ASAN_FLAG(bool, windows_hook_rtl_allocators, false, - "(Windows only) enable hooking of Rtl(Allocate|Free|Size|ReAllocate)Heap.") +ASAN_FLAG( + bool, windows_hook_rtl_allocators, false, + "(Windows only) enable hooking of Rtl(Allocate|Free|Size|ReAllocate)Heap.") diff --git a/libsanitizer/asan/asan_globals.cpp b/libsanitizer/asan/asan_globals.cpp index c77e5357bf9..9d7dbc6f264 100644 --- a/libsanitizer/asan/asan_globals.cpp +++ b/libsanitizer/asan/asan_globals.cpp @@ -154,6 +154,23 @@ static void CheckODRViolationViaIndicator(const Global *g) { } } +// Check ODR violation for given global G by checking if it's already poisoned. +// We use this method in case compiler doesn't use private aliases for global +// variables. +static void CheckODRViolationViaPoisoning(const Global *g) { + if (__asan_region_is_poisoned(g->beg, g->size_with_redzone)) { + // This check may not be enough: if the first global is much larger + // the entire redzone of the second global may be within the first global. + for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) { + if (g->beg == l->g->beg && + (flags()->detect_odr_violation >= 2 || g->size != l->g->size) && + !IsODRViolationSuppressed(g->name)) + ReportODRViolation(g, FindRegistrationSite(g), + l->g, FindRegistrationSite(l->g)); + } + } +} + // Clang provides two different ways for global variables protection: // it can poison the global itself or its private alias. In former // case we may poison same symbol multiple times, that can help us to @@ -199,6 +216,8 @@ static void RegisterGlobal(const Global *g) { // where two globals with the same name are defined in different modules. if (UseODRIndicator(g)) CheckODRViolationViaIndicator(g); + else + CheckODRViolationViaPoisoning(g); } if (CanPoisonMemory()) PoisonRedZones(*g); @@ -208,8 +227,7 @@ static void RegisterGlobal(const Global *g) { list_of_all_globals = l; if (g->has_dynamic_init) { if (!dynamic_init_globals) { - dynamic_init_globals = - new (allocator_for_globals) VectorOfGlobals; // NOLINT + dynamic_init_globals = new (allocator_for_globals) VectorOfGlobals; dynamic_init_globals->reserve(kDynamicInitGlobalsInitialCapacity); } DynInitGlobal dyn_global = { *g, false }; @@ -296,8 +314,7 @@ void PrintGlobalLocation(InternalScopedString *str, const __asan_global &g) { } // namespace __asan // ---------------------- Interface ---------------- {{{1 -using namespace __asan; // NOLINT - +using namespace __asan; // Apply __asan_register_globals to all globals found in the same loaded // executable or shared library as `flag'. The flag tracks whether globals have @@ -345,7 +362,7 @@ void __asan_register_globals(__asan_global *globals, uptr n) { BlockingMutexLock lock(&mu_for_globals); if (!global_registration_site_vector) { global_registration_site_vector = - new (allocator_for_globals) GlobalRegistrationSiteVector; // NOLINT + new (allocator_for_globals) GlobalRegistrationSiteVector; global_registration_site_vector->reserve(128); } GlobalRegistrationSite site = {stack_id, &globals[0], &globals[n - 1]}; diff --git a/libsanitizer/asan/asan_globals_win.cpp b/libsanitizer/asan/asan_globals_win.cpp index ff5fe226b53..19af88ab12b 100644 --- a/libsanitizer/asan/asan_globals_win.cpp +++ b/libsanitizer/asan/asan_globals_win.cpp @@ -15,8 +15,8 @@ namespace __asan { -#pragma section(".ASAN$GA", read, write) // NOLINT -#pragma section(".ASAN$GZ", read, write) // NOLINT +#pragma section(".ASAN$GA", read, write) +#pragma section(".ASAN$GZ", read, write) extern "C" __declspec(allocate(".ASAN$GA")) ALIGNED(sizeof(__asan_global)) __asan_global __asan_globals_start = {}; extern "C" __declspec(allocate(".ASAN$GZ")) @@ -49,8 +49,8 @@ static void unregister_dso_globals() { } // Register globals -#pragma section(".CRT$XCU", long, read) // NOLINT -#pragma section(".CRT$XTX", long, read) // NOLINT +#pragma section(".CRT$XCU", long, read) +#pragma section(".CRT$XTX", long, read) extern "C" __declspec(allocate(".CRT$XCU")) void (*const __asan_dso_reg_hook)() = ®ister_dso_globals; extern "C" __declspec(allocate(".CRT$XTX")) diff --git a/libsanitizer/asan/asan_interceptors.cpp b/libsanitizer/asan/asan_interceptors.cpp index 482e44d83b7..b19cf25c7cd 100644 --- a/libsanitizer/asan/asan_interceptors.cpp +++ b/libsanitizer/asan/asan_interceptors.cpp @@ -79,7 +79,7 @@ int OnExit() { } // namespace __asan // ---------------------- Wrappers ---------------- {{{1 -using namespace __asan; // NOLINT +using namespace __asan; DECLARE_REAL_AND_INTERCEPTOR(void *, malloc, uptr) DECLARE_REAL_AND_INTERCEPTOR(void, free, void *) @@ -164,6 +164,11 @@ DECLARE_REAL_AND_INTERCEPTOR(void, free, void *) ASAN_MEMSET_IMPL(ctx, block, c, size); \ } while (false) +#if CAN_SANITIZE_LEAKS +#define COMMON_INTERCEPTOR_STRERROR() \ + __lsan::ScopedInterceptorDisabler disabler +#endif + #include "sanitizer_common/sanitizer_common_interceptors.inc" #include "sanitizer_common/sanitizer_signal_interceptors.inc" @@ -373,26 +378,26 @@ DEFINE_REAL(char*, index, const char *string, int c) // For both strcat() and strncat() we need to check the validity of |to| // argument irrespective of the |from| length. -INTERCEPTOR(char*, strcat, char *to, const char *from) { // NOLINT - void *ctx; - ASAN_INTERCEPTOR_ENTER(ctx, strcat); // NOLINT - ENSURE_ASAN_INITED(); - if (flags()->replace_str) { - uptr from_length = REAL(strlen)(from); - ASAN_READ_RANGE(ctx, from, from_length + 1); - uptr to_length = REAL(strlen)(to); - ASAN_READ_STRING_OF_LEN(ctx, to, to_length, to_length); - ASAN_WRITE_RANGE(ctx, to + to_length, from_length + 1); - // If the copying actually happens, the |from| string should not overlap - // with the resulting string starting at |to|, which has a length of - // to_length + from_length + 1. - if (from_length > 0) { - CHECK_RANGES_OVERLAP("strcat", to, from_length + to_length + 1, - from, from_length + 1); + INTERCEPTOR(char *, strcat, char *to, const char *from) { + void *ctx; + ASAN_INTERCEPTOR_ENTER(ctx, strcat); + ENSURE_ASAN_INITED(); + if (flags()->replace_str) { + uptr from_length = REAL(strlen)(from); + ASAN_READ_RANGE(ctx, from, from_length + 1); + uptr to_length = REAL(strlen)(to); + ASAN_READ_STRING_OF_LEN(ctx, to, to_length, to_length); + ASAN_WRITE_RANGE(ctx, to + to_length, from_length + 1); + // If the copying actually happens, the |from| string should not overlap + // with the resulting string starting at |to|, which has a length of + // to_length + from_length + 1. + if (from_length > 0) { + CHECK_RANGES_OVERLAP("strcat", to, from_length + to_length + 1, from, + from_length + 1); + } } + return REAL(strcat)(to, from); } - return REAL(strcat)(to, from); // NOLINT -} INTERCEPTOR(char*, strncat, char *to, const char *from, uptr size) { void *ctx; @@ -413,16 +418,17 @@ INTERCEPTOR(char*, strncat, char *to, const char *from, uptr size) { return REAL(strncat)(to, from, size); } -INTERCEPTOR(char*, strcpy, char *to, const char *from) { // NOLINT +INTERCEPTOR(char *, strcpy, char *to, const char *from) { void *ctx; - ASAN_INTERCEPTOR_ENTER(ctx, strcpy); // NOLINT + ASAN_INTERCEPTOR_ENTER(ctx, strcpy); #if SANITIZER_MAC - if (UNLIKELY(!asan_inited)) return REAL(strcpy)(to, from); // NOLINT + if (UNLIKELY(!asan_inited)) + return REAL(strcpy)(to, from); #endif // strcpy is called from malloc_default_purgeable_zone() // in __asan::ReplaceSystemAlloc() on Mac. if (asan_init_is_running) { - return REAL(strcpy)(to, from); // NOLINT + return REAL(strcpy)(to, from); } ENSURE_ASAN_INITED(); if (flags()->replace_str) { @@ -431,7 +437,7 @@ INTERCEPTOR(char*, strcpy, char *to, const char *from) { // NOLINT ASAN_READ_RANGE(ctx, from, from_size); ASAN_WRITE_RANGE(ctx, to, from_size); } - return REAL(strcpy)(to, from); // NOLINT + return REAL(strcpy)(to, from); } INTERCEPTOR(char*, strdup, const char *s) { @@ -479,8 +485,7 @@ INTERCEPTOR(char*, strncpy, char *to, const char *from, uptr size) { return REAL(strncpy)(to, from, size); } -INTERCEPTOR(long, strtol, const char *nptr, // NOLINT - char **endptr, int base) { +INTERCEPTOR(long, strtol, const char *nptr, char **endptr, int base) { void *ctx; ASAN_INTERCEPTOR_ENTER(ctx, strtol); ENSURE_ASAN_INITED(); @@ -488,7 +493,7 @@ INTERCEPTOR(long, strtol, const char *nptr, // NOLINT return REAL(strtol)(nptr, endptr, base); } char *real_endptr; - long result = REAL(strtol)(nptr, &real_endptr, base); // NOLINT + long result = REAL(strtol)(nptr, &real_endptr, base); StrtolFixAndCheck(ctx, nptr, endptr, real_endptr, base); return result; } @@ -514,7 +519,7 @@ INTERCEPTOR(int, atoi, const char *nptr) { return result; } -INTERCEPTOR(long, atol, const char *nptr) { // NOLINT +INTERCEPTOR(long, atol, const char *nptr) { void *ctx; ASAN_INTERCEPTOR_ENTER(ctx, atol); #if SANITIZER_MAC @@ -525,15 +530,14 @@ INTERCEPTOR(long, atol, const char *nptr) { // NOLINT return REAL(atol)(nptr); } char *real_endptr; - long result = REAL(strtol)(nptr, &real_endptr, 10); // NOLINT + long result = REAL(strtol)(nptr, &real_endptr, 10); FixRealStrtolEndptr(nptr, &real_endptr); ASAN_READ_STRING(ctx, nptr, (real_endptr - nptr) + 1); return result; } #if ASAN_INTERCEPT_ATOLL_AND_STRTOLL -INTERCEPTOR(long long, strtoll, const char *nptr, // NOLINT - char **endptr, int base) { +INTERCEPTOR(long long, strtoll, const char *nptr, char **endptr, int base) { void *ctx; ASAN_INTERCEPTOR_ENTER(ctx, strtoll); ENSURE_ASAN_INITED(); @@ -541,12 +545,12 @@ INTERCEPTOR(long long, strtoll, const char *nptr, // NOLINT return REAL(strtoll)(nptr, endptr, base); } char *real_endptr; - long long result = REAL(strtoll)(nptr, &real_endptr, base); // NOLINT + long long result = REAL(strtoll)(nptr, &real_endptr, base); StrtolFixAndCheck(ctx, nptr, endptr, real_endptr, base); return result; } -INTERCEPTOR(long long, atoll, const char *nptr) { // NOLINT +INTERCEPTOR(long long, atoll, const char *nptr) { void *ctx; ASAN_INTERCEPTOR_ENTER(ctx, atoll); ENSURE_ASAN_INITED(); @@ -554,31 +558,66 @@ INTERCEPTOR(long long, atoll, const char *nptr) { // NOLINT return REAL(atoll)(nptr); } char *real_endptr; - long long result = REAL(strtoll)(nptr, &real_endptr, 10); // NOLINT + long long result = REAL(strtoll)(nptr, &real_endptr, 10); FixRealStrtolEndptr(nptr, &real_endptr); ASAN_READ_STRING(ctx, nptr, (real_endptr - nptr) + 1); return result; } #endif // ASAN_INTERCEPT_ATOLL_AND_STRTOLL -#if ASAN_INTERCEPT___CXA_ATEXIT +#if ASAN_INTERCEPT___CXA_ATEXIT || ASAN_INTERCEPT_ATEXIT static void AtCxaAtexit(void *unused) { (void)unused; StopInitOrderChecking(); } +#endif +#if ASAN_INTERCEPT___CXA_ATEXIT INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg, void *dso_handle) { #if SANITIZER_MAC if (UNLIKELY(!asan_inited)) return REAL(__cxa_atexit)(func, arg, dso_handle); #endif ENSURE_ASAN_INITED(); +#if CAN_SANITIZE_LEAKS + __lsan::ScopedInterceptorDisabler disabler; +#endif int res = REAL(__cxa_atexit)(func, arg, dso_handle); REAL(__cxa_atexit)(AtCxaAtexit, nullptr, nullptr); return res; } #endif // ASAN_INTERCEPT___CXA_ATEXIT +#if ASAN_INTERCEPT_ATEXIT +INTERCEPTOR(int, atexit, void (*func)()) { + ENSURE_ASAN_INITED(); +#if CAN_SANITIZE_LEAKS + __lsan::ScopedInterceptorDisabler disabler; +#endif + // Avoid calling real atexit as it is unrechable on at least on Linux. + int res = REAL(__cxa_atexit)((void (*)(void *a))func, nullptr, nullptr); + REAL(__cxa_atexit)(AtCxaAtexit, nullptr, nullptr); + return res; +} +#endif + +#if ASAN_INTERCEPT_PTHREAD_ATFORK +extern "C" { +extern int _pthread_atfork(void (*prepare)(), void (*parent)(), + void (*child)()); +}; + +INTERCEPTOR(int, pthread_atfork, void (*prepare)(), void (*parent)(), + void (*child)()) { +#if CAN_SANITIZE_LEAKS + __lsan::ScopedInterceptorDisabler disabler; +#endif + // REAL(pthread_atfork) cannot be called due to symbol indirections at least + // on NetBSD + return _pthread_atfork(prepare, parent, child); +} +#endif + #if ASAN_INTERCEPT_VFORK DEFINE_REAL(int, vfork) DECLARE_EXTERN_INTERCEPTOR_AND_WRAPPER(int, vfork) @@ -594,8 +633,8 @@ void InitializeAsanInterceptors() { InitializeSignalInterceptors(); // Intercept str* functions. - ASAN_INTERCEPT_FUNC(strcat); // NOLINT - ASAN_INTERCEPT_FUNC(strcpy); // NOLINT + ASAN_INTERCEPT_FUNC(strcat); + ASAN_INTERCEPT_FUNC(strcpy); ASAN_INTERCEPT_FUNC(strncat); ASAN_INTERCEPT_FUNC(strncpy); ASAN_INTERCEPT_FUNC(strdup); @@ -661,6 +700,14 @@ void InitializeAsanInterceptors() { ASAN_INTERCEPT_FUNC(__cxa_atexit); #endif +#if ASAN_INTERCEPT_ATEXIT + ASAN_INTERCEPT_FUNC(atexit); +#endif + +#if ASAN_INTERCEPT_PTHREAD_ATFORK + ASAN_INTERCEPT_FUNC(pthread_atfork); +#endif + #if ASAN_INTERCEPT_VFORK ASAN_INTERCEPT_FUNC(vfork); #endif diff --git a/libsanitizer/asan/asan_interceptors.h b/libsanitizer/asan/asan_interceptors.h index 035a84e1a42..344a64bd83d 100644 --- a/libsanitizer/asan/asan_interceptors.h +++ b/libsanitizer/asan/asan_interceptors.h @@ -80,12 +80,7 @@ void InitializePlatformInterceptors(); #if ASAN_HAS_EXCEPTIONS && !SANITIZER_WINDOWS && !SANITIZER_SOLARIS && \ !SANITIZER_NETBSD # define ASAN_INTERCEPT___CXA_THROW 1 -# if ! defined(ASAN_HAS_CXA_RETHROW_PRIMARY_EXCEPTION) \ - || ASAN_HAS_CXA_RETHROW_PRIMARY_EXCEPTION -# define ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION 1 -# else -# define ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION 0 -# endif +# define ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION 1 # if defined(_GLIBCXX_SJLJ_EXCEPTIONS) || (SANITIZER_IOS && defined(__arm__)) # define ASAN_INTERCEPT__UNWIND_SJLJ_RAISEEXCEPTION 1 # else @@ -104,6 +99,12 @@ void InitializePlatformInterceptors(); # define ASAN_INTERCEPT___CXA_ATEXIT 0 #endif +#if SANITIZER_NETBSD +# define ASAN_INTERCEPT_ATEXIT 1 +#else +# define ASAN_INTERCEPT_ATEXIT 0 +#endif + #if SANITIZER_LINUX && !SANITIZER_ANDROID # define ASAN_INTERCEPT___STRDUP 1 #else @@ -117,6 +118,12 @@ void InitializePlatformInterceptors(); # define ASAN_INTERCEPT_VFORK 0 #endif +#if SANITIZER_NETBSD +# define ASAN_INTERCEPT_PTHREAD_ATFORK 1 +#else +# define ASAN_INTERCEPT_PTHREAD_ATFORK 0 +#endif + DECLARE_REAL(int, memcmp, const void *a1, const void *a2, uptr size) DECLARE_REAL(char*, strchr, const char *str, int c) DECLARE_REAL(SIZE_T, strlen, const char *s) diff --git a/libsanitizer/asan/asan_interceptors_memintrinsics.cpp b/libsanitizer/asan/asan_interceptors_memintrinsics.cpp index 56df60ba681..ccdd5159042 100644 --- a/libsanitizer/asan/asan_interceptors_memintrinsics.cpp +++ b/libsanitizer/asan/asan_interceptors_memintrinsics.cpp @@ -16,7 +16,7 @@ #include "asan_stack.h" #include "asan_suppressions.h" -using namespace __asan; // NOLINT +using namespace __asan; void *__asan_memcpy(void *to, const void *from, uptr size) { ASAN_MEMCPY_IMPL(nullptr, to, from, size); diff --git a/libsanitizer/asan/asan_mac.cpp b/libsanitizer/asan/asan_mac.cpp index 769d499672d..a8d3f5d3473 100644 --- a/libsanitizer/asan/asan_mac.cpp +++ b/libsanitizer/asan/asan_mac.cpp @@ -205,7 +205,7 @@ void asan_dispatch_call_block_and_release(void *block) { } // namespace __asan -using namespace __asan; // NOLINT +using namespace __asan; // Wrap |ctxt| and |func| into an asan_block_context_t. // The caller retains control of the allocated context. diff --git a/libsanitizer/asan/asan_malloc_linux.cpp b/libsanitizer/asan/asan_malloc_linux.cpp index 706bc39f0c4..faa8968a5d0 100644 --- a/libsanitizer/asan/asan_malloc_linux.cpp +++ b/libsanitizer/asan/asan_malloc_linux.cpp @@ -27,7 +27,7 @@ #include "asan_stack.h" // ---------------------- Replacement functions ---------------- {{{1 -using namespace __asan; // NOLINT +using namespace __asan; static uptr allocated_for_dlsym; static uptr last_dlsym_alloc_size_in_words; diff --git a/libsanitizer/asan/asan_malloc_win.cpp b/libsanitizer/asan/asan_malloc_win.cpp index 291d411ea79..13c6f652119 100644 --- a/libsanitizer/asan/asan_malloc_win.cpp +++ b/libsanitizer/asan/asan_malloc_win.cpp @@ -54,7 +54,7 @@ size_t WINAPI HeapSize(HANDLE hHeap, DWORD dwFlags, LPCVOID lpMem); BOOL WINAPI HeapValidate(HANDLE hHeap, DWORD dwFlags, LPCVOID lpMem); } -using namespace __asan; // NOLINT +using namespace __asan; // MT: Simply defining functions with the same signature in *.obj // files overrides the standard functions in the CRT. @@ -528,10 +528,11 @@ void ReplaceSystemMalloc() { (uptr)WRAP(RtlAllocateHeap), (uptr *)&REAL(RtlAllocateHeap)); } else { -#define INTERCEPT_UCRT_FUNCTION(func) \ - if (!INTERCEPT_FUNCTION_DLLIMPORT("ucrtbase.dll", \ - "api-ms-win-core-heap-l1-1-0.dll", func)) \ - VPrintf(2, "Failed to intercept ucrtbase.dll import %s\n", #func); +#define INTERCEPT_UCRT_FUNCTION(func) \ + if (!INTERCEPT_FUNCTION_DLLIMPORT( \ + "ucrtbase.dll", "api-ms-win-core-heap-l1-1-0.dll", func)) { \ + VPrintf(2, "Failed to intercept ucrtbase.dll import %s\n", #func); \ + } INTERCEPT_UCRT_FUNCTION(HeapAlloc); INTERCEPT_UCRT_FUNCTION(HeapFree); INTERCEPT_UCRT_FUNCTION(HeapReAlloc); diff --git a/libsanitizer/asan/asan_mapping.h b/libsanitizer/asan/asan_mapping.h index 09be904270c..41fb49ee46d 100644 --- a/libsanitizer/asan/asan_mapping.h +++ b/libsanitizer/asan/asan_mapping.h @@ -163,7 +163,7 @@ static const u64 kDefaultShort64bitShadowOffset = static const u64 kAArch64_ShadowOffset64 = 1ULL << 36; static const u64 kMIPS32_ShadowOffset32 = 0x0aaa0000; static const u64 kMIPS64_ShadowOffset64 = 1ULL << 37; -static const u64 kPPC64_ShadowOffset64 = 1ULL << 41; +static const u64 kPPC64_ShadowOffset64 = 1ULL << 44; static const u64 kSystemZ_ShadowOffset64 = 1ULL << 52; static const u64 kSPARC64_ShadowOffset64 = 1ULL << 43; // 0x80000000000 static const u64 kFreeBSD_ShadowOffset32 = 1ULL << 30; // 0x40000000 diff --git a/libsanitizer/asan/asan_new_delete.cpp b/libsanitizer/asan/asan_new_delete.cpp index c15e208094e..5dfcc00fd5d 100644 --- a/libsanitizer/asan/asan_new_delete.cpp +++ b/libsanitizer/asan/asan_new_delete.cpp @@ -48,7 +48,7 @@ COMMENT_EXPORT("??_V@YAXPAX@Z") // operator delete[] #define CXX_OPERATOR_ATTRIBUTE INTERCEPTOR_ATTRIBUTE #endif -using namespace __asan; // NOLINT +using namespace __asan; // FreeBSD prior v9.2 have wrong definition of 'size_t'. // http://svnweb.freebsd.org/base?view=revision&revision=232261 diff --git a/libsanitizer/asan/asan_poisoning.cpp b/libsanitizer/asan/asan_poisoning.cpp index 6b36be7d1cd..f3fbe684e2c 100644 --- a/libsanitizer/asan/asan_poisoning.cpp +++ b/libsanitizer/asan/asan_poisoning.cpp @@ -92,7 +92,7 @@ void AsanPoisonOrUnpoisonIntraObjectRedzone(uptr ptr, uptr size, bool poison) { } // namespace __asan // ---------------------- Interface ---------------- {{{1 -using namespace __asan; // NOLINT +using namespace __asan; // Current implementation of __asan_(un)poison_memory_region doesn't check // that user program (un)poisons the memory it owns. It poisons memory diff --git a/libsanitizer/asan/asan_report.cpp b/libsanitizer/asan/asan_report.cpp index d36b0b4c594..2e6ce436d03 100644 --- a/libsanitizer/asan/asan_report.cpp +++ b/libsanitizer/asan/asan_report.cpp @@ -410,8 +410,12 @@ static bool IsInvalidPointerPair(uptr a1, uptr a2) { static INLINE void CheckForInvalidPointerPair(void *p1, void *p2) { switch (flags()->detect_invalid_pointer_pairs) { - case 0 : return; - case 1 : if (p1 == nullptr || p2 == nullptr) return; break; + case 0: + return; + case 1: + if (p1 == nullptr || p2 == nullptr) + return; + break; } uptr a1 = reinterpret_cast(p1); @@ -472,7 +476,7 @@ void ReportGenericError(uptr pc, uptr bp, uptr sp, uptr addr, bool is_write, } // namespace __asan // --------------------------- Interface --------------------- {{{1 -using namespace __asan; // NOLINT +using namespace __asan; void __asan_report_error(uptr pc, uptr bp, uptr sp, uptr addr, int is_write, uptr access_size, u32 exp) { diff --git a/libsanitizer/asan/asan_rtems.cpp b/libsanitizer/asan/asan_rtems.cpp index 360d5780a3f..ecd568c5981 100644 --- a/libsanitizer/asan/asan_rtems.cpp +++ b/libsanitizer/asan/asan_rtems.cpp @@ -181,11 +181,11 @@ static void ThreadStartHook(void *hook, uptr os_id) { asanThreadRegistry().GetThreadLocked(thread->tid())->status; DCHECK(status == ThreadStatusCreated || status == ThreadStatusRunning); // Determine whether we are starting or restarting the thread. - if (status == ThreadStatusCreated) + if (status == ThreadStatusCreated) { // In lieu of AsanThread::ThreadStart. asanThreadRegistry().StartThread(thread->tid(), os_id, ThreadType::Regular, nullptr); - else { + } else { // In a thread restart, a thread may resume execution at an // arbitrary function entry point, with its stack and TLS state // reset. We unpoison the stack in that case. diff --git a/libsanitizer/asan/asan_rtl.cpp b/libsanitizer/asan/asan_rtl.cpp index b16ca950518..594d7752eea 100644 --- a/libsanitizer/asan/asan_rtl.cpp +++ b/libsanitizer/asan/asan_rtl.cpp @@ -402,7 +402,6 @@ static void AsanInitInternal() { asan_init_is_running = true; CacheBinaryName(); - CheckASLR(); // Initialize flags. This must be done early, because most of the // initialization steps look at flags(). @@ -450,6 +449,7 @@ static void AsanInitInternal() { SetLowLevelAllocateCallback(OnLowLevelAllocate); InitializeAsanInterceptors(); + CheckASLR(); // Enable system log ("adb logcat") on Android. // Doing this before interceptors are initialized crashes in: @@ -542,7 +542,7 @@ void AsanInitFromRtl() { // (and thus normal initializers from .preinit_array or modules haven't run). class AsanInitializer { -public: // NOLINT + public: AsanInitializer() { AsanInitFromRtl(); } @@ -554,7 +554,7 @@ static AsanInitializer asan_initializer; } // namespace __asan // ---------------------- Interface ---------------- {{{1 -using namespace __asan; // NOLINT +using namespace __asan; void NOINLINE __asan_handle_no_return() { if (asan_init_is_running) diff --git a/libsanitizer/asan/asan_scariness_score.h b/libsanitizer/asan/asan_scariness_score.h index 9e7ba47d82d..3932973c225 100644 --- a/libsanitizer/asan/asan_scariness_score.h +++ b/libsanitizer/asan/asan_scariness_score.h @@ -43,7 +43,7 @@ struct ScarinessScoreBase { internal_strlcat(descr, "-", sizeof(descr)); internal_strlcat(descr, reason, sizeof(descr)); score += add_to_score; - }; + } int GetScore() const { return score; } const char *GetDescription() const { return descr; } void Print() const { diff --git a/libsanitizer/asan/asan_shadow_setup.cpp b/libsanitizer/asan/asan_shadow_setup.cpp index fc9bf51e1b5..17324932a86 100644 --- a/libsanitizer/asan/asan_shadow_setup.cpp +++ b/libsanitizer/asan/asan_shadow_setup.cpp @@ -30,14 +30,13 @@ void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name) { CHECK_EQ(((end + 1) % GetMmapGranularity()), 0); uptr size = end - beg + 1; DecreaseTotalMmap(size); // Don't count the shadow against mmap_limit_mb. - if (!MmapFixedNoReserve(beg, size, name)) { + if (!MmapFixedSuperNoReserve(beg, size, name)) { Report( "ReserveShadowMemoryRange failed while trying to map 0x%zx bytes. " "Perhaps you're using ulimit -v\n", size); Abort(); } - SetShadowRegionHugePageMode(beg, size); if (common_flags()->use_madv_dontdump) DontDumpShadowMemory(beg, size); } diff --git a/libsanitizer/asan/asan_stats.cpp b/libsanitizer/asan/asan_stats.cpp index bc4e8c15cc1..00ded8f5ef5 100644 --- a/libsanitizer/asan/asan_stats.cpp +++ b/libsanitizer/asan/asan_stats.cpp @@ -133,7 +133,7 @@ static void PrintAccumulatedStats() { } // namespace __asan // ---------------------- Interface ---------------- {{{1 -using namespace __asan; // NOLINT +using namespace __asan; uptr __sanitizer_get_current_allocated_bytes() { AsanStats stats; diff --git a/libsanitizer/asan/asan_suppressions.cpp b/libsanitizer/asan/asan_suppressions.cpp index a9c0d107694..8cb2c3e3b9b 100644 --- a/libsanitizer/asan/asan_suppressions.cpp +++ b/libsanitizer/asan/asan_suppressions.cpp @@ -36,7 +36,7 @@ SANITIZER_INTERFACE_WEAK_DEF(const char *, __asan_default_suppressions, void) { void InitializeSuppressions() { CHECK_EQ(nullptr, suppression_ctx); - suppression_ctx = new (suppression_placeholder) // NOLINT + suppression_ctx = new (suppression_placeholder) SuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes)); suppression_ctx->ParseFromFile(flags()->suppressions); if (&__asan_default_suppressions) diff --git a/libsanitizer/asan/asan_thread.cpp b/libsanitizer/asan/asan_thread.cpp index d48b3414dd5..6734d9a1668 100644 --- a/libsanitizer/asan/asan_thread.cpp +++ b/libsanitizer/asan/asan_thread.cpp @@ -367,8 +367,9 @@ uptr AsanThread::GetStackVariableShadowStart(uptr addr) { } else if (has_fake_stack()) { bottom = fake_stack()->AddrIsInFakeStack(addr); CHECK(bottom); - } else + } else { return 0; + } uptr aligned_addr = RoundDownTo(addr, SANITIZER_WORDSIZE / 8); // align addr. u8 *shadow_ptr = (u8*)MemToShadow(aligned_addr); @@ -505,7 +506,7 @@ void EnsureMainThreadIDIsCorrect() { } // namespace __lsan // ---------------------- Interface ---------------- {{{1 -using namespace __asan; // NOLINT +using namespace __asan; extern "C" { SANITIZER_INTERFACE_ATTRIBUTE diff --git a/libsanitizer/asan/asan_win.cpp b/libsanitizer/asan/asan_win.cpp index f8b98ca3366..417892aaedd 100644 --- a/libsanitizer/asan/asan_win.cpp +++ b/libsanitizer/asan/asan_win.cpp @@ -29,7 +29,7 @@ #include "sanitizer_common/sanitizer_win.h" #include "sanitizer_common/sanitizer_win_defs.h" -using namespace __asan; // NOLINT +using namespace __asan; extern "C" { SANITIZER_INTERFACE_ATTRIBUTE @@ -106,7 +106,7 @@ INTERCEPTOR_WINAPI(void, RaiseException, void *a, void *b, void *c, void *d) { INTERCEPTOR_WINAPI(EXCEPTION_DISPOSITION, __C_specific_handler, _EXCEPTION_RECORD *a, void *b, _CONTEXT *c, - _DISPATCHER_CONTEXT *d) { // NOLINT + _DISPATCHER_CONTEXT *d) { CHECK(REAL(__C_specific_handler)); __asan_handle_no_return(); return REAL(__C_specific_handler)(a, b, c, d); @@ -362,7 +362,7 @@ bool HandleDlopenInit() { // beginning of C++ initialization. We set our priority to XCAB to run // immediately after the CRT runs. This way, our exception filter is called // first and we can delegate to their filter if appropriate. -#pragma section(".CRT$XCAB", long, read) // NOLINT +#pragma section(".CRT$XCAB", long, read) __declspec(allocate(".CRT$XCAB")) int (*__intercept_seh)() = __asan_set_seh_filter; @@ -375,7 +375,7 @@ static void NTAPI asan_thread_init(void *module, DWORD reason, void *reserved) { __asan_init(); } -#pragma section(".CRT$XLAB", long, read) // NOLINT +#pragma section(".CRT$XLAB", long, read) __declspec(allocate(".CRT$XLAB")) void(NTAPI *__asan_tls_init)( void *, unsigned long, void *) = asan_thread_init; #endif @@ -389,7 +389,7 @@ static void NTAPI asan_thread_exit(void *module, DWORD reason, void *reserved) { } } -#pragma section(".CRT$XLY", long, read) // NOLINT +#pragma section(".CRT$XLY", long, read) __declspec(allocate(".CRT$XLY")) void(NTAPI *__asan_tls_exit)( void *, unsigned long, void *) = asan_thread_exit; diff --git a/libsanitizer/asan/asan_win_dll_thunk.cpp b/libsanitizer/asan/asan_win_dll_thunk.cpp index 95eee5eed0d..a5671cc9dff 100644 --- a/libsanitizer/asan/asan_win_dll_thunk.cpp +++ b/libsanitizer/asan/asan_win_dll_thunk.cpp @@ -67,10 +67,10 @@ INTERCEPT_LIBRARY_FUNCTION(memcmp); INTERCEPT_LIBRARY_FUNCTION(memcpy); INTERCEPT_LIBRARY_FUNCTION(memmove); INTERCEPT_LIBRARY_FUNCTION(memset); -INTERCEPT_LIBRARY_FUNCTION(strcat); // NOLINT +INTERCEPT_LIBRARY_FUNCTION(strcat); INTERCEPT_LIBRARY_FUNCTION(strchr); INTERCEPT_LIBRARY_FUNCTION(strcmp); -INTERCEPT_LIBRARY_FUNCTION(strcpy); // NOLINT +INTERCEPT_LIBRARY_FUNCTION(strcpy); INTERCEPT_LIBRARY_FUNCTION(strcspn); INTERCEPT_LIBRARY_FUNCTION(strdup); INTERCEPT_LIBRARY_FUNCTION(strlen); @@ -135,7 +135,7 @@ static int asan_dll_thunk_init() { return 0; } -#pragma section(".CRT$XIB", long, read) // NOLINT +#pragma section(".CRT$XIB", long, read) __declspec(allocate(".CRT$XIB")) int (*__asan_preinit)() = asan_dll_thunk_init; static void WINAPI asan_thread_init(void *mod, unsigned long reason, @@ -143,7 +143,7 @@ static void WINAPI asan_thread_init(void *mod, unsigned long reason, if (reason == /*DLL_PROCESS_ATTACH=*/1) asan_dll_thunk_init(); } -#pragma section(".CRT$XLAB", long, read) // NOLINT +#pragma section(".CRT$XLAB", long, read) __declspec(allocate(".CRT$XLAB")) void (WINAPI *__asan_tls_init)(void *, unsigned long, void *) = asan_thread_init; diff --git a/libsanitizer/asan/asan_win_dynamic_runtime_thunk.cpp b/libsanitizer/asan/asan_win_dynamic_runtime_thunk.cpp index 5bd457a22b6..f0b5ec9eef7 100644 --- a/libsanitizer/asan/asan_win_dynamic_runtime_thunk.cpp +++ b/libsanitizer/asan/asan_win_dynamic_runtime_thunk.cpp @@ -32,12 +32,12 @@ #include "asan_interface.inc" // First, declare CRT sections we'll be using in this file -#pragma section(".CRT$XIB", long, read) // NOLINT -#pragma section(".CRT$XID", long, read) // NOLINT -#pragma section(".CRT$XCAB", long, read) // NOLINT -#pragma section(".CRT$XTW", long, read) // NOLINT -#pragma section(".CRT$XTY", long, read) // NOLINT -#pragma section(".CRT$XLAB", long, read) // NOLINT +#pragma section(".CRT$XIB", long, read) +#pragma section(".CRT$XID", long, read) +#pragma section(".CRT$XCAB", long, read) +#pragma section(".CRT$XTW", long, read) +#pragma section(".CRT$XTY", long, read) +#pragma section(".CRT$XLAB", long, read) //////////////////////////////////////////////////////////////////////////////// // Define a copy of __asan_option_detect_stack_use_after_return that should be diff --git a/libsanitizer/include/sanitizer/dfsan_interface.h b/libsanitizer/include/sanitizer/dfsan_interface.h index c189ee55790..81546e5df71 100644 --- a/libsanitizer/include/sanitizer/dfsan_interface.h +++ b/libsanitizer/include/sanitizer/dfsan_interface.h @@ -112,7 +112,7 @@ void dfsan_weak_hook_strncmp(void *caller_pc, const char *s1, const char *s2, } // extern "C" template -void dfsan_set_label(dfsan_label label, T &data) { // NOLINT +void dfsan_set_label(dfsan_label label, T &data) { // NOLINT dfsan_set_label(label, (void *)&data, sizeof(T)); } diff --git a/libsanitizer/include/sanitizer/tsan_interface_atomic.h b/libsanitizer/include/sanitizer/tsan_interface_atomic.h index 9ce0411917d..8052bc1d56b 100644 --- a/libsanitizer/include/sanitizer/tsan_interface_atomic.h +++ b/libsanitizer/include/sanitizer/tsan_interface_atomic.h @@ -17,10 +17,10 @@ extern "C" { #endif -typedef char __tsan_atomic8; -typedef short __tsan_atomic16; // NOLINT -typedef int __tsan_atomic32; -typedef long __tsan_atomic64; // NOLINT +typedef char __tsan_atomic8; +typedef short __tsan_atomic16; +typedef int __tsan_atomic32; +typedef long __tsan_atomic64; #if defined(__SIZEOF_INT128__) \ || (__clang_major__ * 100 + __clang_minor__ >= 302) __extension__ typedef __int128 __tsan_atomic128; diff --git a/libsanitizer/include/sanitizer/ubsan_interface.h b/libsanitizer/include/sanitizer/ubsan_interface.h new file mode 100644 index 00000000000..59fc6c3c184 --- /dev/null +++ b/libsanitizer/include/sanitizer/ubsan_interface.h @@ -0,0 +1,32 @@ +//===-- sanitizer/ubsan_interface.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 UBSanitizer (UBSan). +// +// Public interface header. +//===----------------------------------------------------------------------===// +#ifndef SANITIZER_UBSAN_INTERFACE_H +#define SANITIZER_UBSAN_INTERFACE_H + +#ifdef __cplusplus +extern "C" { +#endif +/// User-provided default option settings. +/// +/// You can provide your own implementation of this function to return a string +/// containing UBSan runtime options (for example, +/// verbosity=1:halt_on_error=0). +/// +/// \returns Default options string. +const char* __ubsan_default_options(void); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // SANITIZER_UBSAN_INTERFACE_H diff --git a/libsanitizer/interception/interception.h b/libsanitizer/interception/interception.h index dacfa5ede28..d27a8ccf92a 100644 --- a/libsanitizer/interception/interception.h +++ b/libsanitizer/interception/interception.h @@ -272,9 +272,9 @@ const interpose_substitution substitution_##func_name[] \ // INTERCEPT_FUNCTION macro, only its name. namespace __interception { #if defined(_WIN64) -typedef unsigned long long uptr; // NOLINT +typedef unsigned long long uptr; #else -typedef unsigned long uptr; // NOLINT +typedef unsigned long uptr; #endif // _WIN64 } // namespace __interception diff --git a/libsanitizer/interception/interception_win.cpp b/libsanitizer/interception/interception_win.cpp index b94e214fdff..1a1c327e612 100644 --- a/libsanitizer/interception/interception_win.cpp +++ b/libsanitizer/interception/interception_win.cpp @@ -883,8 +883,8 @@ uptr InternalGetProcAddress(void *module, const char *func_name) { // Check that the module header is full and present. RVAPtr dos_stub(module, 0); RVAPtr headers(module, dos_stub->e_lfanew); - if (!module || dos_stub->e_magic != IMAGE_DOS_SIGNATURE || // "MZ" - headers->Signature != IMAGE_NT_SIGNATURE || // "PE\0\0" + if (!module || dos_stub->e_magic != IMAGE_DOS_SIGNATURE || // "MZ" + headers->Signature != IMAGE_NT_SIGNATURE || // "PE\0\0" headers->FileHeader.SizeOfOptionalHeader < sizeof(IMAGE_OPTIONAL_HEADER)) { return 0; @@ -963,8 +963,8 @@ bool OverrideImportedFunction(const char *module_to_patch, // Check that the module header is full and present. RVAPtr dos_stub(module, 0); RVAPtr headers(module, dos_stub->e_lfanew); - if (!module || dos_stub->e_magic != IMAGE_DOS_SIGNATURE || // "MZ" - headers->Signature != IMAGE_NT_SIGNATURE || // "PE\0\0" + if (!module || dos_stub->e_magic != IMAGE_DOS_SIGNATURE || // "MZ" + headers->Signature != IMAGE_NT_SIGNATURE || // "PE\0\0" headers->FileHeader.SizeOfOptionalHeader < sizeof(IMAGE_OPTIONAL_HEADER)) { return false; diff --git a/libsanitizer/lsan/lsan.cpp b/libsanitizer/lsan/lsan.cpp index 5b5f6198a69..4ce03046ffb 100644 --- a/libsanitizer/lsan/lsan.cpp +++ b/libsanitizer/lsan/lsan.cpp @@ -50,7 +50,7 @@ void __sanitizer::BufferedStackTrace::UnwindImpl( } } -using namespace __lsan; // NOLINT +using namespace __lsan; static void InitializeFlags() { // Set all the default values. @@ -89,7 +89,7 @@ static void InitializeFlags() { static void OnStackUnwind(const SignalContext &sig, const void *, BufferedStackTrace *stack) { - stack->Unwind(sig.pc, sig.bp, sig.context, + stack->Unwind(StackTrace::GetNextInstructionPc(sig.pc), sig.bp, sig.context, common_flags()->fast_unwind_on_fatal); } diff --git a/libsanitizer/lsan/lsan_common.cpp b/libsanitizer/lsan/lsan_common.cpp index c39fab97c64..9ff9f4c5d1c 100644 --- a/libsanitizer/lsan/lsan_common.cpp +++ b/libsanitizer/lsan/lsan_common.cpp @@ -84,7 +84,7 @@ static const char kStdSuppressions[] = void InitializeSuppressions() { CHECK_EQ(nullptr, suppression_ctx); - suppression_ctx = new (suppression_placeholder) // NOLINT + suppression_ctx = new (suppression_placeholder) SuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes)); suppression_ctx->ParseFromFile(flags()->suppressions); if (&__lsan_default_suppressions) @@ -104,7 +104,7 @@ InternalMmapVector const *GetRootRegions() { return root_regions; } void InitializeRootRegions() { CHECK(!root_regions); ALIGNED(64) static char placeholder[sizeof(InternalMmapVector)]; - root_regions = new (placeholder) InternalMmapVector(); // NOLINT + root_regions = new (placeholder) InternalMmapVector(); } const char *MaybeCallLsanDefaultOptions() { @@ -162,7 +162,7 @@ void ScanRangeForPointers(uptr begin, uptr end, uptr pp = begin; if (pp % alignment) pp = pp + alignment - pp % alignment; - for (; pp + sizeof(void *) <= end; pp += alignment) { // NOLINT + for (; pp + sizeof(void *) <= end; pp += alignment) { void *p = *reinterpret_cast(pp); if (!CanBeAHeapPointer(reinterpret_cast(p))) continue; uptr chunk = PointsIntoChunk(p); @@ -535,7 +535,7 @@ static void ReportIfNotSuspended(ThreadContextBase *tctx, void *arg) { if (i >= suspended_threads.size() || suspended_threads[i] != tctx->os_id) Report("Running thread %d was not suspended. False leaks are possible.\n", tctx->os_id); - }; + } } static void ReportUnsuspendedThreads( @@ -570,11 +570,7 @@ static bool CheckForLeaks() { EnsureMainThreadIDIsCorrect(); CheckForLeaksParam param; param.success = false; - LockThreadRegistry(); - LockAllocator(); - DoStopTheWorld(CheckForLeaksCallback, ¶m); - UnlockAllocator(); - UnlockThreadRegistry(); + LockStuffAndStopTheWorld(CheckForLeaksCallback, ¶m); if (!param.success) { Report("LeakSanitizer has encountered a fatal error.\n"); @@ -794,7 +790,7 @@ void EnableInThisThread() { } } #endif // CAN_SANITIZE_LEAKS -using namespace __lsan; // NOLINT +using namespace __lsan; extern "C" { SANITIZER_INTERFACE_ATTRIBUTE diff --git a/libsanitizer/lsan/lsan_common.h b/libsanitizer/lsan/lsan_common.h index 58dc00faaee..d24abe31b71 100644 --- a/libsanitizer/lsan/lsan_common.h +++ b/libsanitizer/lsan/lsan_common.h @@ -129,8 +129,9 @@ struct RootRegion { InternalMmapVector const *GetRootRegions(); void ScanRootRegion(Frontier *frontier, RootRegion const ®ion, uptr region_begin, uptr region_end, bool is_readable); -// Run stoptheworld while holding any platform-specific locks. -void DoStopTheWorld(StopTheWorldCallback callback, void* argument); +// Run stoptheworld while holding any platform-specific locks, as well as the +// allocator and thread registry locks. +void LockStuffAndStopTheWorld(StopTheWorldCallback callback, void* argument); void ScanRangeForPointers(uptr begin, uptr end, Frontier *frontier, diff --git a/libsanitizer/lsan/lsan_common_linux.cpp b/libsanitizer/lsan/lsan_common_linux.cpp index 9ce27a983b5..ea1a4a2f569 100644 --- a/libsanitizer/lsan/lsan_common_linux.cpp +++ b/libsanitizer/lsan/lsan_common_linux.cpp @@ -115,10 +115,14 @@ void HandleLeaks() { if (common_flags()->exitcode) Die(); } -static int DoStopTheWorldCallback(struct dl_phdr_info *info, size_t size, - void *data) { +static int LockStuffAndStopTheWorldCallback(struct dl_phdr_info *info, + size_t size, void *data) { + LockThreadRegistry(); + LockAllocator(); DoStopTheWorldParam *param = reinterpret_cast(data); StopTheWorld(param->callback, param->argument); + UnlockAllocator(); + UnlockThreadRegistry(); return 1; } @@ -130,9 +134,9 @@ static int DoStopTheWorldCallback(struct dl_phdr_info *info, size_t size, // while holding the libdl lock in the parent thread, we can safely reenter it // in the tracer. The solution is to run stoptheworld from a dl_iterate_phdr() // callback in the parent thread. -void DoStopTheWorld(StopTheWorldCallback callback, void *argument) { +void LockStuffAndStopTheWorld(StopTheWorldCallback callback, void *argument) { DoStopTheWorldParam param = {callback, argument}; - dl_iterate_phdr(DoStopTheWorldCallback, ¶m); + dl_iterate_phdr(LockStuffAndStopTheWorldCallback, ¶m); } } // namespace __lsan diff --git a/libsanitizer/lsan/lsan_common_mac.cpp b/libsanitizer/lsan/lsan_common_mac.cpp index 5204a6624ed..c1804e93c11 100644 --- a/libsanitizer/lsan/lsan_common_mac.cpp +++ b/libsanitizer/lsan/lsan_common_mac.cpp @@ -193,8 +193,12 @@ void ProcessPlatformSpecificAllocations(Frontier *frontier) { // causes rare race conditions. void HandleLeaks() {} -void DoStopTheWorld(StopTheWorldCallback callback, void *argument) { +void LockStuffAndStopTheWorld(StopTheWorldCallback callback, void *argument) { + LockThreadRegistry(); + LockAllocator(); StopTheWorld(callback, argument); + UnlockAllocator(); + UnlockThreadRegistry(); } } // namespace __lsan diff --git a/libsanitizer/lsan/lsan_interceptors.cpp b/libsanitizer/lsan/lsan_interceptors.cpp index f06d5fff706..f642bb807bc 100644 --- a/libsanitizer/lsan/lsan_interceptors.cpp +++ b/libsanitizer/lsan/lsan_interceptors.cpp @@ -345,6 +345,55 @@ INTERCEPTOR(void, thr_exit, tid_t *state) { #define LSAN_MAYBE_INTERCEPT_THR_EXIT #endif +#if SANITIZER_INTERCEPT___CXA_ATEXIT +INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg, + void *dso_handle) { + __lsan::ScopedInterceptorDisabler disabler; + return REAL(__cxa_atexit)(func, arg, dso_handle); +} +#define LSAN_MAYBE_INTERCEPT___CXA_ATEXIT INTERCEPT_FUNCTION(__cxa_atexit) +#else +#define LSAN_MAYBE_INTERCEPT___CXA_ATEXIT +#endif + +#if SANITIZER_INTERCEPT_ATEXIT +INTERCEPTOR(int, atexit, void (*f)()) { + __lsan::ScopedInterceptorDisabler disabler; + return REAL(__cxa_atexit)((void (*)(void *a))f, 0, 0); +} +#define LSAN_MAYBE_INTERCEPT_ATEXIT INTERCEPT_FUNCTION(atexit) +#else +#define LSAN_MAYBE_INTERCEPT_ATEXIT +#endif + +#if SANITIZER_INTERCEPT_PTHREAD_ATFORK +extern "C" { +extern int _pthread_atfork(void (*prepare)(), void (*parent)(), + void (*child)()); +}; + +INTERCEPTOR(int, pthread_atfork, void (*prepare)(), void (*parent)(), + void (*child)()) { + __lsan::ScopedInterceptorDisabler disabler; + // REAL(pthread_atfork) cannot be called due to symbol indirections at least + // on NetBSD + return _pthread_atfork(prepare, parent, child); +} +#define LSAN_MAYBE_INTERCEPT_PTHREAD_ATFORK INTERCEPT_FUNCTION(pthread_atfork) +#else +#define LSAN_MAYBE_INTERCEPT_PTHREAD_ATFORK +#endif + +#if SANITIZER_INTERCEPT_STRERROR +INTERCEPTOR(char *, strerror, int errnum) { + __lsan::ScopedInterceptorDisabler disabler; + return REAL(strerror)(errnum); +} +#define LSAN_MAYBE_INTERCEPT_STRERROR INTERCEPT_FUNCTION(strerror) +#else +#define LSAN_MAYBE_INTERCEPT_STRERROR +#endif + struct ThreadParam { void *(*callback)(void *arg); void *param; @@ -454,6 +503,12 @@ void InitializeInterceptors() { LSAN_MAYBE_INTERCEPT__LWP_EXIT; LSAN_MAYBE_INTERCEPT_THR_EXIT; + LSAN_MAYBE_INTERCEPT___CXA_ATEXIT; + LSAN_MAYBE_INTERCEPT_ATEXIT; + LSAN_MAYBE_INTERCEPT_PTHREAD_ATFORK; + + LSAN_MAYBE_INTERCEPT_STRERROR; + #if !SANITIZER_NETBSD && !SANITIZER_FREEBSD if (pthread_key_create(&g_thread_finalize_key, &thread_finalize)) { Report("LeakSanitizer: failed to create thread key.\n"); diff --git a/libsanitizer/lsan/lsan_mac.cpp b/libsanitizer/lsan/lsan_mac.cpp index 7bcd9c828ef..b96893e2801 100644 --- a/libsanitizer/lsan/lsan_mac.cpp +++ b/libsanitizer/lsan/lsan_mac.cpp @@ -90,7 +90,7 @@ extern "C" void lsan_dispatch_call_block_and_release(void *block) { } // namespace __lsan -using namespace __lsan; // NOLINT +using namespace __lsan; // Wrap |ctxt| and |func| into an lsan_block_context_t. // The caller retains control of the allocated context. diff --git a/libsanitizer/merge.sh b/libsanitizer/merge.sh index 168fbbc9729..2f74fbef260 100755 --- a/libsanitizer/merge.sh +++ b/libsanitizer/merge.sh @@ -74,7 +74,6 @@ merge lib/tsan/rtl tsan merge lib/sanitizer_common sanitizer_common merge lib/interception interception merge lib/ubsan ubsan -merge lib/BlocksRuntime/ BlocksRuntime # Need to merge lib/builtins/assembly.h file: mkdir -p builtins diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_checks.h b/libsanitizer/sanitizer_common/sanitizer_allocator_checks.h index f436ce9ecde..fc426f0e74f 100644 --- a/libsanitizer/sanitizer_common/sanitizer_allocator_checks.h +++ b/libsanitizer/sanitizer_common/sanitizer_allocator_checks.h @@ -54,7 +54,7 @@ INLINE bool CheckAlignedAllocAlignmentAndSize(uptr alignment, uptr size) { // and a multiple of sizeof(void *). INLINE bool CheckPosixMemalignAlignment(uptr alignment) { return alignment != 0 && IsPowerOfTwo(alignment) && - (alignment % sizeof(void *)) == 0; // NOLINT + (alignment % sizeof(void *)) == 0; } // Returns true if calloc(size, n) call overflows on size*n calculation. diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_report.cpp b/libsanitizer/sanitizer_common/sanitizer_allocator_report.cpp index dbcf2b7bf26..d74e08010d5 100644 --- a/libsanitizer/sanitizer_common/sanitizer_allocator_report.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_allocator_report.cpp @@ -106,10 +106,11 @@ void NORETURN ReportInvalidPosixMemalignAlignment(uptr alignment, { ScopedAllocatorErrorReport report("invalid-posix-memalign-alignment", stack); - Report("ERROR: %s: invalid alignment requested in " - "posix_memalign: %zd, alignment must be a power of two and a " - "multiple of sizeof(void*) == %zd\n", SanitizerToolName, alignment, - sizeof(void*)); // NOLINT + Report( + "ERROR: %s: invalid alignment requested in " + "posix_memalign: %zd, alignment must be a power of two and a " + "multiple of sizeof(void*) == %zd\n", + SanitizerToolName, alignment, sizeof(void *)); } Die(); } diff --git a/libsanitizer/sanitizer_common/sanitizer_asm.h b/libsanitizer/sanitizer_common/sanitizer_asm.h index 184d118d97d..803af3285e1 100644 --- a/libsanitizer/sanitizer_common/sanitizer_asm.h +++ b/libsanitizer/sanitizer_common/sanitizer_asm.h @@ -60,7 +60,9 @@ #if defined(__ELF__) && (defined(__GNU__) || defined(__FreeBSD__) || \ defined(__Fuchsia__) || defined(__linux__)) -#define NO_EXEC_STACK_DIRECTIVE .section .note.GNU-stack,"",%progbits // NOLINT +// clang-format off +#define NO_EXEC_STACK_DIRECTIVE .section .note.GNU-stack,"",%progbits // NOLINT +// clang-format on #else #define NO_EXEC_STACK_DIRECTIVE #endif diff --git a/libsanitizer/sanitizer_common/sanitizer_atomic_msvc.h b/libsanitizer/sanitizer_common/sanitizer_atomic_msvc.h index a249657d661..6a7c5465dcb 100644 --- a/libsanitizer/sanitizer_common/sanitizer_atomic_msvc.h +++ b/libsanitizer/sanitizer_common/sanitizer_atomic_msvc.h @@ -20,44 +20,35 @@ extern "C" void _mm_mfence(); #pragma intrinsic(_mm_mfence) extern "C" void _mm_pause(); #pragma intrinsic(_mm_pause) -extern "C" char _InterlockedExchange8( // NOLINT - char volatile *Addend, char Value); // NOLINT +extern "C" char _InterlockedExchange8(char volatile *Addend, char Value); #pragma intrinsic(_InterlockedExchange8) -extern "C" short _InterlockedExchange16( // NOLINT - short volatile *Addend, short Value); // NOLINT +extern "C" short _InterlockedExchange16(short volatile *Addend, short Value); #pragma intrinsic(_InterlockedExchange16) -extern "C" long _InterlockedExchange( // NOLINT - long volatile *Addend, long Value); // NOLINT +extern "C" long _InterlockedExchange(long volatile *Addend, long Value); #pragma intrinsic(_InterlockedExchange) -extern "C" long _InterlockedExchangeAdd( // NOLINT - long volatile * Addend, long Value); // NOLINT +extern "C" long _InterlockedExchangeAdd(long volatile *Addend, long Value); #pragma intrinsic(_InterlockedExchangeAdd) -extern "C" char _InterlockedCompareExchange8( // NOLINT - char volatile *Destination, // NOLINT - char Exchange, char Comparand); // NOLINT +extern "C" char _InterlockedCompareExchange8(char volatile *Destination, + char Exchange, char Comparand); #pragma intrinsic(_InterlockedCompareExchange8) -extern "C" short _InterlockedCompareExchange16( // NOLINT - short volatile *Destination, // NOLINT - short Exchange, short Comparand); // NOLINT +extern "C" short _InterlockedCompareExchange16(short volatile *Destination, + short Exchange, short Comparand); #pragma intrinsic(_InterlockedCompareExchange16) -extern "C" -long long _InterlockedCompareExchange64( // NOLINT - long long volatile *Destination, // NOLINT - long long Exchange, long long Comparand); // NOLINT +extern "C" long long _InterlockedCompareExchange64( + long long volatile *Destination, long long Exchange, long long Comparand); #pragma intrinsic(_InterlockedCompareExchange64) extern "C" void *_InterlockedCompareExchangePointer( void *volatile *Destination, void *Exchange, void *Comparand); #pragma intrinsic(_InterlockedCompareExchangePointer) -extern "C" -long __cdecl _InterlockedCompareExchange( // NOLINT - long volatile *Destination, // NOLINT - long Exchange, long Comparand); // NOLINT +extern "C" long __cdecl _InterlockedCompareExchange(long volatile *Destination, + long Exchange, + long Comparand); #pragma intrinsic(_InterlockedCompareExchange) #ifdef _WIN64 -extern "C" long long _InterlockedExchangeAdd64( // NOLINT - long long volatile * Addend, long long Value); // NOLINT +extern "C" long long _InterlockedExchangeAdd64(long long volatile *Addend, + long long Value); #pragma intrinsic(_InterlockedExchangeAdd64) #endif @@ -115,8 +106,8 @@ INLINE u32 atomic_fetch_add(volatile atomic_uint32_t *a, u32 v, memory_order mo) { (void)mo; DCHECK(!((uptr)a % sizeof(*a))); - return (u32)_InterlockedExchangeAdd( - (volatile long*)&a->val_dont_use, (long)v); // NOLINT + return (u32)_InterlockedExchangeAdd((volatile long *)&a->val_dont_use, + (long)v); } INLINE uptr atomic_fetch_add(volatile atomic_uintptr_t *a, @@ -124,11 +115,11 @@ INLINE uptr atomic_fetch_add(volatile atomic_uintptr_t *a, (void)mo; DCHECK(!((uptr)a % sizeof(*a))); #ifdef _WIN64 - return (uptr)_InterlockedExchangeAdd64( - (volatile long long*)&a->val_dont_use, (long long)v); // NOLINT + return (uptr)_InterlockedExchangeAdd64((volatile long long *)&a->val_dont_use, + (long long)v); #else - return (uptr)_InterlockedExchangeAdd( - (volatile long*)&a->val_dont_use, (long)v); // NOLINT + return (uptr)_InterlockedExchangeAdd((volatile long *)&a->val_dont_use, + (long)v); #endif } @@ -136,8 +127,8 @@ INLINE u32 atomic_fetch_sub(volatile atomic_uint32_t *a, u32 v, memory_order mo) { (void)mo; DCHECK(!((uptr)a % sizeof(*a))); - return (u32)_InterlockedExchangeAdd( - (volatile long*)&a->val_dont_use, -(long)v); // NOLINT + return (u32)_InterlockedExchangeAdd((volatile long *)&a->val_dont_use, + -(long)v); } INLINE uptr atomic_fetch_sub(volatile atomic_uintptr_t *a, @@ -145,11 +136,11 @@ INLINE uptr atomic_fetch_sub(volatile atomic_uintptr_t *a, (void)mo; DCHECK(!((uptr)a % sizeof(*a))); #ifdef _WIN64 - return (uptr)_InterlockedExchangeAdd64( - (volatile long long*)&a->val_dont_use, -(long long)v); // NOLINT + return (uptr)_InterlockedExchangeAdd64((volatile long long *)&a->val_dont_use, + -(long long)v); #else - return (uptr)_InterlockedExchangeAdd( - (volatile long*)&a->val_dont_use, -(long)v); // NOLINT + return (uptr)_InterlockedExchangeAdd((volatile long *)&a->val_dont_use, + -(long)v); #endif } diff --git a/libsanitizer/sanitizer_common/sanitizer_common.cpp b/libsanitizer/sanitizer_common/sanitizer_common.cpp index 451c9e526e0..f5f9f49d8cf 100644 --- a/libsanitizer/sanitizer_common/sanitizer_common.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_common.cpp @@ -323,7 +323,7 @@ static int InstallMallocFreeHooks(void (*malloc_hook)(const void *, uptr), } // namespace __sanitizer -using namespace __sanitizer; // NOLINT +using namespace __sanitizer; extern "C" { SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_report_error_summary, diff --git a/libsanitizer/sanitizer_common/sanitizer_common.h b/libsanitizer/sanitizer_common/sanitizer_common.h index 4f0f16d3532..87b8f02b5b7 100644 --- a/libsanitizer/sanitizer_common/sanitizer_common.h +++ b/libsanitizer/sanitizer_common/sanitizer_common.h @@ -100,6 +100,8 @@ void UnmapOrDie(void *addr, uptr size); void *MmapOrDieOnFatalError(uptr size, const char *mem_type); bool MmapFixedNoReserve(uptr fixed_addr, uptr size, const char *name = nullptr) WARN_UNUSED_RESULT; +bool MmapFixedSuperNoReserve(uptr fixed_addr, uptr size, + const char *name = nullptr) WARN_UNUSED_RESULT; void *MmapNoReserveOrDie(uptr size, const char *mem_type); void *MmapFixedOrDie(uptr fixed_addr, uptr size, const char *name = nullptr); // Behaves just like MmapFixedOrDie, but tolerates out of memory condition, in @@ -337,18 +339,18 @@ void ReportMmapWriteExec(int prot); // Math #if SANITIZER_WINDOWS && !defined(__clang__) && !defined(__GNUC__) extern "C" { -unsigned char _BitScanForward(unsigned long *index, unsigned long mask); // NOLINT -unsigned char _BitScanReverse(unsigned long *index, unsigned long mask); // NOLINT +unsigned char _BitScanForward(unsigned long *index, unsigned long mask); +unsigned char _BitScanReverse(unsigned long *index, unsigned long mask); #if defined(_WIN64) -unsigned char _BitScanForward64(unsigned long *index, unsigned __int64 mask); // NOLINT -unsigned char _BitScanReverse64(unsigned long *index, unsigned __int64 mask); // NOLINT +unsigned char _BitScanForward64(unsigned long *index, unsigned __int64 mask); +unsigned char _BitScanReverse64(unsigned long *index, unsigned __int64 mask); #endif } #endif INLINE uptr MostSignificantSetBitIndex(uptr x) { CHECK_NE(x, 0U); - unsigned long up; // NOLINT + unsigned long up; #if !SANITIZER_WINDOWS || defined(__clang__) || defined(__GNUC__) # ifdef _WIN64 up = SANITIZER_WORDSIZE - 1 - __builtin_clzll(x); @@ -365,7 +367,7 @@ INLINE uptr MostSignificantSetBitIndex(uptr x) { INLINE uptr LeastSignificantSetBitIndex(uptr x) { CHECK_NE(x, 0U); - unsigned long up; // NOLINT + unsigned long up; #if !SANITIZER_WINDOWS || defined(__clang__) || defined(__GNUC__) # ifdef _WIN64 up = __builtin_ctzll(x); @@ -879,6 +881,11 @@ struct SignalContext { bool is_memory_access; enum WriteFlag { UNKNOWN, READ, WRITE } write_flag; + // In some cases the kernel cannot provide the true faulting address; `addr` + // will be zero then. This field allows to distinguish between these cases + // and dereferences of null. + bool is_true_faulting_addr; + // VS2013 doesn't implement unrestricted unions, so we need a trivial default // constructor SignalContext() = default; @@ -891,7 +898,8 @@ struct SignalContext { context(context), addr(GetAddress()), is_memory_access(IsMemoryAccess()), - write_flag(GetWriteFlag()) { + write_flag(GetWriteFlag()), + is_true_faulting_addr(IsTrueFaultingAddress()) { InitPcSpBp(); } @@ -912,6 +920,7 @@ struct SignalContext { uptr GetAddress() const; WriteFlag GetWriteFlag() const; bool IsMemoryAccess() const; + bool IsTrueFaultingAddress() const; }; void InitializePlatformEarly(); @@ -971,7 +980,7 @@ INLINE u32 GetNumberOfCPUsCached() { } // namespace __sanitizer inline void *operator new(__sanitizer::operator_new_size_type size, - __sanitizer::LowLevelAllocator &alloc) { + __sanitizer::LowLevelAllocator &alloc) { // NOLINT return alloc.Allocate(size); } diff --git a/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc b/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc index 9975f5321a5..50e3558b52e 100644 --- a/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc +++ b/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc @@ -36,6 +36,7 @@ // COMMON_INTERCEPTOR_MMAP_IMPL // COMMON_INTERCEPTOR_COPY_STRING // COMMON_INTERCEPTOR_STRNDUP_IMPL +// COMMON_INTERCEPTOR_STRERROR //===----------------------------------------------------------------------===// #include "interception/interception.h" @@ -301,6 +302,10 @@ bool PlatformHasDifferentMemcpyAndMemmove(); return new_mem; #endif +#ifndef COMMON_INTERCEPTOR_STRERROR +#define COMMON_INTERCEPTOR_STRERROR() {} +#endif + struct FileMetadata { // For open_memstream(). char **addr; @@ -1267,9 +1272,8 @@ INTERCEPTOR(int, puts, char *s) { #endif #if SANITIZER_INTERCEPT_PRCTL -INTERCEPTOR(int, prctl, int option, unsigned long arg2, - unsigned long arg3, // NOLINT - unsigned long arg4, unsigned long arg5) { // NOLINT +INTERCEPTOR(int, prctl, int option, unsigned long arg2, unsigned long arg3, + unsigned long arg4, unsigned long arg5) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, prctl, option, arg2, arg3, arg4, arg5); static const int PR_SET_NAME = 15; @@ -1701,13 +1705,13 @@ INTERCEPTOR(int, __fprintf_chk, __sanitizer_FILE *stream, SIZE_T size, FORMAT_INTERCEPTOR_IMPL(__fprintf_chk, vfprintf, stream, format) #endif -INTERCEPTOR(int, sprintf, char *str, const char *format, ...) // NOLINT -FORMAT_INTERCEPTOR_IMPL(sprintf, vsprintf, str, format) // NOLINT +INTERCEPTOR(int, sprintf, char *str, const char *format, ...) +FORMAT_INTERCEPTOR_IMPL(sprintf, vsprintf, str, format) #if SANITIZER_INTERCEPT___PRINTF_CHK INTERCEPTOR(int, __sprintf_chk, char *str, int flag, SIZE_T size_to, - const char *format, ...) // NOLINT -FORMAT_INTERCEPTOR_IMPL(__sprintf_chk, vsprintf, str, format) // NOLINT + const char *format, ...) +FORMAT_INTERCEPTOR_IMPL(__sprintf_chk, vsprintf, str, format) #endif INTERCEPTOR(int, snprintf, char *str, SIZE_T size, const char *format, ...) @@ -1715,8 +1719,8 @@ FORMAT_INTERCEPTOR_IMPL(snprintf, vsnprintf, str, size, format) #if SANITIZER_INTERCEPT___PRINTF_CHK INTERCEPTOR(int, __snprintf_chk, char *str, SIZE_T size, int flag, - SIZE_T size_to, const char *format, ...) // NOLINT -FORMAT_INTERCEPTOR_IMPL(__snprintf_chk, vsnprintf, str, size, format) // NOLINT + SIZE_T size_to, const char *format, ...) +FORMAT_INTERCEPTOR_IMPL(__snprintf_chk, vsnprintf, str, size, format) #endif INTERCEPTOR(int, asprintf, char **strp, const char *format, ...) @@ -3071,13 +3075,14 @@ INTERCEPTOR(int, sendmmsg, int fd, struct __sanitizer_mmsghdr *msgvec, COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd); } int res = REAL(sendmmsg)(fd, msgvec, vlen, flags); - if (res >= 0 && msgvec) + if (res >= 0 && msgvec) { for (int i = 0; i < res; ++i) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, &msgvec[i].msg_len, sizeof(msgvec[i].msg_len)); if (common_flags()->intercept_send) read_msghdr(ctx, &msgvec[i].msg_hdr, msgvec[i].msg_len); } + } return res; } #define INIT_SENDMMSG COMMON_INTERCEPT_FUNCTION(sendmmsg); @@ -3208,20 +3213,21 @@ INTERCEPTOR(uptr, ptrace, int request, int pid, void *addr, void *data) { __sanitizer_iovec local_iovec; if (data) { - if (request == ptrace_setregs) + if (request == ptrace_setregs) { COMMON_INTERCEPTOR_READ_RANGE(ctx, data, struct_user_regs_struct_sz); - else if (request == ptrace_setfpregs) + } else if (request == ptrace_setfpregs) { COMMON_INTERCEPTOR_READ_RANGE(ctx, data, struct_user_fpregs_struct_sz); - else if (request == ptrace_setfpxregs) + } else if (request == ptrace_setfpxregs) { COMMON_INTERCEPTOR_READ_RANGE(ctx, data, struct_user_fpxregs_struct_sz); - else if (request == ptrace_setvfpregs) + } else if (request == ptrace_setvfpregs) { COMMON_INTERCEPTOR_READ_RANGE(ctx, data, struct_user_vfpregs_struct_sz); - else if (request == ptrace_setsiginfo) + } else if (request == ptrace_setsiginfo) { COMMON_INTERCEPTOR_READ_RANGE(ctx, data, siginfo_t_sz); + // Some kernel might zero the iovec::iov_base in case of invalid // write access. In this case copy the invalid address for further // inspection. - else if (request == ptrace_setregset || request == ptrace_getregset) { + } else if (request == ptrace_setregset || request == ptrace_getregset) { __sanitizer_iovec *iovec = (__sanitizer_iovec*)data; COMMON_INTERCEPTOR_READ_RANGE(ctx, iovec, sizeof(*iovec)); local_iovec = *iovec; @@ -3238,19 +3244,19 @@ INTERCEPTOR(uptr, ptrace, int request, int pid, void *addr, void *data) { if (!res && data) { // Note that PEEK* requests assign different meaning to the return value. // This function does not handle them (nor does it need to). - if (request == ptrace_getregs) + if (request == ptrace_getregs) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, struct_user_regs_struct_sz); - else if (request == ptrace_getfpregs) + } else if (request == ptrace_getfpregs) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, struct_user_fpregs_struct_sz); - else if (request == ptrace_getfpxregs) + } else if (request == ptrace_getfpxregs) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, struct_user_fpxregs_struct_sz); - else if (request == ptrace_getvfpregs) + } else if (request == ptrace_getvfpregs) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, struct_user_vfpregs_struct_sz); - else if (request == ptrace_getsiginfo) + } else if (request == ptrace_getsiginfo) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, siginfo_t_sz); - else if (request == ptrace_geteventmsg) + } else if (request == ptrace_geteventmsg) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, sizeof(unsigned long)); - else if (request == ptrace_getregset) { + } else if (request == ptrace_getregset) { __sanitizer_iovec *iovec = (__sanitizer_iovec*)data; COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iovec, sizeof(*iovec)); COMMON_INTERCEPTOR_WRITE_RANGE(ctx, local_iovec.iov_base, @@ -3676,6 +3682,7 @@ INTERCEPTOR(int, sched_getparam, int pid, void *param) { INTERCEPTOR(char *, strerror, int errnum) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, strerror, errnum); + COMMON_INTERCEPTOR_STRERROR(); char *res = REAL(strerror)(errnum); if (res) COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, REAL(strlen)(res) + 1); return res; @@ -6716,7 +6723,7 @@ INTERCEPTOR(wchar_t *, wcscat, wchar_t *dst, const wchar_t *src) { COMMON_INTERCEPTOR_READ_RANGE(ctx, dst, (dst_size + 1) * sizeof(wchar_t)); COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst + dst_size, (src_size + 1) * sizeof(wchar_t)); - return REAL(wcscat)(dst, src); // NOLINT + return REAL(wcscat)(dst, src); } INTERCEPTOR(wchar_t *, wcsncat, wchar_t *dst, const wchar_t *src, SIZE_T n) { @@ -6729,7 +6736,7 @@ INTERCEPTOR(wchar_t *, wcsncat, wchar_t *dst, const wchar_t *src, SIZE_T n) { COMMON_INTERCEPTOR_READ_RANGE(ctx, dst, (dst_size + 1) * sizeof(wchar_t)); COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst + dst_size, (src_size + 1) * sizeof(wchar_t)); - return REAL(wcsncat)(dst, src, n); // NOLINT + return REAL(wcsncat)(dst, src, n); } #define INIT_WCSCAT \ COMMON_INTERCEPT_FUNCTION(wcscat); \ @@ -7843,10 +7850,11 @@ INTERCEPTOR(int, modctl, int operation, void *argp) { if (iov) COMMON_INTERCEPTOR_WRITE_RANGE( ctx, iov->iov_base, Min(iov_len, iov->iov_len)); - } else if (operation == modctl_exists) + } else if (operation == modctl_exists) { ret = REAL(modctl)(operation, argp); - else + } else { ret = REAL(modctl)(operation, argp); + } return ret; } @@ -9565,11 +9573,60 @@ INTERCEPTOR(SSIZE_T, getrandom, void *buf, SIZE_T buflen, unsigned int flags) { #define INIT_GETRANDOM #endif +#if SANITIZER_INTERCEPT_CRYPT +INTERCEPTOR(char *, crypt, char *key, char *salt) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, crypt, key, salt); + COMMON_INTERCEPTOR_READ_RANGE(ctx, key, internal_strlen(key) + 1); + COMMON_INTERCEPTOR_READ_RANGE(ctx, salt, internal_strlen(salt) + 1); + char *res = REAL(crypt)(key, salt); + if (res != nullptr) + COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, internal_strlen(res) + 1); + return res; +} +#define INIT_CRYPT COMMON_INTERCEPT_FUNCTION(crypt); +#else +#define INIT_CRYPT +#endif + +#if SANITIZER_INTERCEPT_CRYPT_R +INTERCEPTOR(char *, crypt_r, char *key, char *salt, void *data) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, crypt_r, key, salt, data); + COMMON_INTERCEPTOR_READ_RANGE(ctx, key, internal_strlen(key) + 1); + COMMON_INTERCEPTOR_READ_RANGE(ctx, salt, internal_strlen(salt) + 1); + char *res = REAL(crypt_r)(key, salt, data); + if (res != nullptr) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, + __sanitizer::struct_crypt_data_sz); + COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, internal_strlen(res) + 1); + } + return res; +} +#define INIT_CRYPT_R COMMON_INTERCEPT_FUNCTION(crypt_r); +#else +#define INIT_CRYPT_R +#endif + +#if SANITIZER_INTERCEPT_GETENTROPY +INTERCEPTOR(int, getentropy, void *buf, SIZE_T buflen) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getentropy, buf, buflen); + int r = REAL(getentropy)(buf, buflen); + if (r == 0) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, buflen); + } + return r; +} +#define INIT_GETENTROPY COMMON_INTERCEPT_FUNCTION(getentropy) +#else +#define INIT_GETENTROPY +#endif + static void InitializeCommonInterceptors() { #if SI_POSIX static u64 metadata_mem[sizeof(MetadataHashMap) / sizeof(u64) + 1]; - interceptor_metadata_map = - new ((void *)&metadata_mem) MetadataHashMap(); // NOLINT + interceptor_metadata_map = new ((void *)&metadata_mem) MetadataHashMap(); #endif INIT_MMAP; @@ -9864,6 +9921,9 @@ static void InitializeCommonInterceptors() { INIT_GETUSERSHELL; INIT_SL_INIT; INIT_GETRANDOM; + INIT_CRYPT; + INIT_CRYPT_R; + INIT_GETENTROPY; INIT___PRINTF_CHK; } diff --git a/libsanitizer/sanitizer_common/sanitizer_common_interface.inc b/libsanitizer/sanitizer_common/sanitizer_common_interface.inc index c72554973b0..c78b6e10b68 100644 --- a/libsanitizer/sanitizer_common/sanitizer_common_interface.inc +++ b/libsanitizer/sanitizer_common/sanitizer_common_interface.inc @@ -14,6 +14,7 @@ INTERFACE_FUNCTION(__sanitizer_set_death_callback) INTERFACE_FUNCTION(__sanitizer_set_report_path) INTERFACE_FUNCTION(__sanitizer_set_report_fd) INTERFACE_FUNCTION(__sanitizer_verify_contiguous_container) +INTERFACE_WEAK_FUNCTION(__sanitizer_on_print) INTERFACE_WEAK_FUNCTION(__sanitizer_report_error_summary) INTERFACE_WEAK_FUNCTION(__sanitizer_sandbox_on_notify) // Sanitizer weak hooks diff --git a/libsanitizer/sanitizer_common/sanitizer_coverage_fuchsia.cpp b/libsanitizer/sanitizer_common/sanitizer_coverage_fuchsia.cpp index 5451d1e758b..f18cee66b84 100644 --- a/libsanitizer/sanitizer_common/sanitizer_coverage_fuchsia.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_coverage_fuchsia.cpp @@ -36,7 +36,7 @@ #include #include -using namespace __sanitizer; // NOLINT +using namespace __sanitizer; namespace __sancov { namespace { @@ -198,8 +198,8 @@ void InitializeCoverage(bool enabled, const char *dir) { } // namespace __sanitizer extern "C" { -SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_dump_coverage( // NOLINT - const uptr *pcs, uptr len) { +SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_dump_coverage(const uptr *pcs, + uptr len) { UNIMPLEMENTED(); } diff --git a/libsanitizer/sanitizer_common/sanitizer_coverage_libcdep_new.cpp b/libsanitizer/sanitizer_common/sanitizer_coverage_libcdep_new.cpp index ad137f936ff..6a75792f926 100644 --- a/libsanitizer/sanitizer_common/sanitizer_coverage_libcdep_new.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_coverage_libcdep_new.cpp @@ -166,8 +166,8 @@ void InitializeCoverage(bool enabled, const char *dir) { } // namespace __sanitizer extern "C" { -SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_dump_coverage( // NOLINT - const uptr* pcs, uptr len) { +SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_dump_coverage(const uptr* pcs, + uptr len) { return __sancov::SanitizerDumpCoverage(pcs, len); } diff --git a/libsanitizer/sanitizer_common/sanitizer_coverage_win_sections.cpp b/libsanitizer/sanitizer_common/sanitizer_coverage_win_sections.cpp index 40184bbb913..e7d6563393c 100644 --- a/libsanitizer/sanitizer_common/sanitizer_coverage_win_sections.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_coverage_win_sections.cpp @@ -31,7 +31,7 @@ extern "C" { // Use uint64_t so the linker won't need to add any padding if it tries to word // align the start of the 8-bit counters array. The array will always start 8 // bytes after __start_sancov_cntrs. -#pragma section(".SCOV$CA", read, write) // NOLINT +#pragma section(".SCOV$CA", read, write) __declspec(allocate(".SCOV$CA")) uint64_t __start___sancov_cntrs = 0; // Even though we said not to align __stop__sancov_cntrs (using the "align" @@ -41,13 +41,13 @@ __declspec(allocate(".SCOV$CA")) uint64_t __start___sancov_cntrs = 0; // padding would be added to align .SCOVP$Z, However, if .SCOV$CZ section is 1 // byte, the linker won't try to align it on an 8-byte boundary, so use a // uint8_t for __stop_sancov_cntrs. -#pragma section(".SCOV$CZ", read, write) // NOLINT +#pragma section(".SCOV$CZ", read, write) __declspec(allocate(".SCOV$CZ")) __declspec(align(1)) uint8_t __stop___sancov_cntrs = 0; -#pragma section(".SCOV$GA", read, write) // NOLINT +#pragma section(".SCOV$GA", read, write) __declspec(allocate(".SCOV$GA")) uint64_t __start___sancov_guards = 0; -#pragma section(".SCOV$GZ", read, write) // NOLINT +#pragma section(".SCOV$GZ", read, write) __declspec(allocate(".SCOV$GZ")) __declspec(align(1)) uint8_t __stop___sancov_guards = 0; @@ -56,9 +56,9 @@ __declspec(allocate(".SCOV$GZ")) __declspec(align(1)) uint8_t // constant it should be merged with the .rdata section. #pragma comment(linker, "/MERGE:.SCOV=.data") -#pragma section(".SCOVP$A", read) // NOLINT +#pragma section(".SCOVP$A", read) __declspec(allocate(".SCOVP$A")) uint64_t __start___sancov_pcs = 0; -#pragma section(".SCOVP$Z", read) // NOLINT +#pragma section(".SCOVP$Z", read) __declspec(allocate(".SCOVP$Z")) __declspec(align(1)) uint8_t __stop___sancov_pcs = 0; diff --git a/libsanitizer/sanitizer_common/sanitizer_file.cpp b/libsanitizer/sanitizer_common/sanitizer_file.cpp index c8c0b33cd6c..79930d79425 100644 --- a/libsanitizer/sanitizer_common/sanitizer_file.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_file.cpp @@ -199,7 +199,7 @@ char *FindPathToBinary(const char *name) { } // namespace __sanitizer -using namespace __sanitizer; // NOLINT +using namespace __sanitizer; extern "C" { void __sanitizer_set_report_path(const char *path) { diff --git a/libsanitizer/sanitizer_common/sanitizer_flag_parser.cpp b/libsanitizer/sanitizer_common/sanitizer_flag_parser.cpp index 4831814b6df..1e2bc665261 100644 --- a/libsanitizer/sanitizer_common/sanitizer_flag_parser.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_flag_parser.cpp @@ -83,8 +83,9 @@ void FlagParser::parse_flag(const char *env_option_name) { Printf("%s: ERROR: expected '=' in %s\n", SanitizerToolName, env_option_name); Die(); - } else + } else { fatal_error("expected '='"); + } } char *name = ll_strndup(buf_ + name_start, pos_ - name_start); diff --git a/libsanitizer/sanitizer_common/sanitizer_flag_parser.h b/libsanitizer/sanitizer_common/sanitizer_flag_parser.h index 8e12700bbe8..c24ad25626b 100644 --- a/libsanitizer/sanitizer_common/sanitizer_flag_parser.h +++ b/libsanitizer/sanitizer_common/sanitizer_flag_parser.h @@ -24,7 +24,7 @@ class FlagHandlerBase { virtual bool Parse(const char *value) { return false; } protected: - ~FlagHandlerBase() {}; + ~FlagHandlerBase() {} }; template @@ -144,7 +144,7 @@ class FlagParser { template static void RegisterFlag(FlagParser *parser, const char *name, const char *desc, T *var) { - FlagHandler *fh = new (FlagParser::Alloc) FlagHandler(var); // NOLINT + FlagHandler *fh = new (FlagParser::Alloc) FlagHandler(var); parser->RegisterHandler(name, fh, desc); } diff --git a/libsanitizer/sanitizer_common/sanitizer_flags.cpp b/libsanitizer/sanitizer_common/sanitizer_flags.cpp index acc7ed39cb0..66a0a5579ed 100644 --- a/libsanitizer/sanitizer_common/sanitizer_flags.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_flags.cpp @@ -92,11 +92,11 @@ class FlagHandlerInclude : public FlagHandlerBase { }; void RegisterIncludeFlags(FlagParser *parser, CommonFlags *cf) { - FlagHandlerInclude *fh_include = new (FlagParser::Alloc) // NOLINT + FlagHandlerInclude *fh_include = new (FlagParser::Alloc) FlagHandlerInclude(parser, /*ignore_missing*/ false); parser->RegisterHandler("include", fh_include, "read more options from the given file"); - FlagHandlerInclude *fh_include_if_exists = new (FlagParser::Alloc) // NOLINT + FlagHandlerInclude *fh_include_if_exists = new (FlagParser::Alloc) FlagHandlerInclude(parser, /*ignore_missing*/ true); parser->RegisterHandler( "include_if_exists", fh_include_if_exists, diff --git a/libsanitizer/sanitizer_common/sanitizer_fuchsia.cpp b/libsanitizer/sanitizer_common/sanitizer_fuchsia.cpp index 3dc6863a03a..6e2c6137f0c 100644 --- a/libsanitizer/sanitizer_common/sanitizer_fuchsia.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_fuchsia.cpp @@ -502,7 +502,7 @@ uptr GetRSS() { UNIMPLEMENTED(); } } // namespace __sanitizer -using namespace __sanitizer; // NOLINT +using namespace __sanitizer; extern "C" { void __sanitizer_startup_hook(int argc, char **argv, char **envp, diff --git a/libsanitizer/sanitizer_common/sanitizer_getauxval.h b/libsanitizer/sanitizer_common/sanitizer_getauxval.h index cbd1af12c04..86ad3a5e2c2 100644 --- a/libsanitizer/sanitizer_common/sanitizer_getauxval.h +++ b/libsanitizer/sanitizer_common/sanitizer_getauxval.h @@ -9,6 +9,7 @@ // Common getauxval() guards and definitions. // getauxval() is not defined until glibc version 2.16, or until API level 21 // for Android. +// Implement the getauxval() compat function for NetBSD. // //===----------------------------------------------------------------------===// @@ -16,15 +17,10 @@ #define SANITIZER_GETAUXVAL_H #include "sanitizer_platform.h" +#include "sanitizer_glibc_version.h" #if SANITIZER_LINUX || SANITIZER_FUCHSIA -# include - -# ifndef __GLIBC_PREREQ -# define __GLIBC_PREREQ(x, y) 0 -# endif - # if __GLIBC_PREREQ(2, 16) || (SANITIZER_ANDROID && __ANDROID_API__ >= 21) || \ SANITIZER_FUCHSIA # define SANITIZER_USE_GETAUXVAL 1 @@ -38,10 +34,26 @@ // The weak getauxval definition allows to check for the function at runtime. // This is useful for Android, when compiled at a lower API level yet running // on a more recent platform that offers the function. -extern "C" SANITIZER_WEAK_ATTRIBUTE -unsigned long getauxval(unsigned long type); // NOLINT +extern "C" SANITIZER_WEAK_ATTRIBUTE unsigned long getauxval(unsigned long type); # endif -#endif // SANITIZER_LINUX || SANITIZER_FUCHSIA +#elif SANITIZER_NETBSD + +#define SANITIZER_USE_GETAUXVAL 1 + +#include +#include + +static inline decltype(AuxInfo::a_v) getauxval(decltype(AuxInfo::a_type) type) { + for (const AuxInfo *aux = (const AuxInfo *)_dlauxinfo(); + aux->a_type != AT_NULL; ++aux) { + if (type == aux->a_type) + return aux->a_v; + } + + return 0; +} + +#endif #endif // SANITIZER_GETAUXVAL_H diff --git a/libsanitizer/sanitizer_common/sanitizer_glibc_version.h b/libsanitizer/sanitizer_common/sanitizer_glibc_version.h new file mode 100644 index 00000000000..47175f20aa0 --- /dev/null +++ b/libsanitizer/sanitizer_common/sanitizer_glibc_version.h @@ -0,0 +1,26 @@ +//===-- sanitizer_glibc_version.h -----------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of Sanitizer common code. +// +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_GLIBC_VERSION_H +#define SANITIZER_GLIBC_VERSION_H + +#include "sanitizer_platform.h" + +#if SANITIZER_LINUX || SANITIZER_FUCHSIA +#include +#endif + +#ifndef __GLIBC_PREREQ +#define __GLIBC_PREREQ(x, y) 0 +#endif + +#endif diff --git a/libsanitizer/sanitizer_common/sanitizer_interceptors_ioctl_netbsd.inc b/libsanitizer/sanitizer_common/sanitizer_interceptors_ioctl_netbsd.inc index 1ec73827b8b..03ef7c1788c 100644 --- a/libsanitizer/sanitizer_common/sanitizer_interceptors_ioctl_netbsd.inc +++ b/libsanitizer/sanitizer_common/sanitizer_interceptors_ioctl_netbsd.inc @@ -1404,7 +1404,7 @@ static void ioctl_table_fill() { _(SNDCTL_DSP_SKIP, NONE, 0); _(SNDCTL_DSP_SILENCE, NONE, 0); #undef _ -} +} // NOLINT static bool ioctl_initialized = false; diff --git a/libsanitizer/sanitizer_common/sanitizer_internal_defs.h b/libsanitizer/sanitizer_common/sanitizer_internal_defs.h index e0c6506bed5..00226305e07 100644 --- a/libsanitizer/sanitizer_common/sanitizer_internal_defs.h +++ b/libsanitizer/sanitizer_common/sanitizer_internal_defs.h @@ -133,27 +133,27 @@ namespace __sanitizer { #if defined(_WIN64) // 64-bit Windows uses LLP64 data model. -typedef unsigned long long uptr; // NOLINT -typedef signed long long sptr; // NOLINT +typedef unsigned long long uptr; +typedef signed long long sptr; #else -typedef unsigned long uptr; // NOLINT -typedef signed long sptr; // NOLINT +typedef unsigned long uptr; +typedef signed long sptr; #endif // defined(_WIN64) #if defined(__x86_64__) // Since x32 uses ILP32 data model in 64-bit hardware mode, we must use // 64-bit pointer to unwind stack frame. -typedef unsigned long long uhwptr; // NOLINT +typedef unsigned long long uhwptr; #else -typedef uptr uhwptr; // NOLINT +typedef uptr uhwptr; #endif typedef unsigned char u8; -typedef unsigned short u16; // NOLINT +typedef unsigned short u16; typedef unsigned int u32; -typedef unsigned long long u64; // NOLINT -typedef signed char s8; -typedef signed short s16; // NOLINT -typedef signed int s32; -typedef signed long long s64; // NOLINT +typedef unsigned long long u64; +typedef signed char s8; +typedef signed short s16; +typedef signed int s32; +typedef signed long long s64; #if SANITIZER_WINDOWS // On Windows, files are HANDLE, which is a synonim of void*. // Use void* to avoid including everywhere. @@ -264,7 +264,7 @@ typedef ALIGNED(1) s64 us64; #if SANITIZER_WINDOWS } // namespace __sanitizer -typedef unsigned long DWORD; // NOLINT +typedef unsigned long DWORD; namespace __sanitizer { typedef DWORD thread_return_t; # define THREAD_CALLING_CONV __stdcall @@ -419,18 +419,41 @@ inline void Trap() { } // namespace __sanitizer -namespace __asan { using namespace __sanitizer; } // NOLINT -namespace __dsan { using namespace __sanitizer; } // NOLINT -namespace __dfsan { using namespace __sanitizer; } // NOLINT -namespace __lsan { using namespace __sanitizer; } // NOLINT -namespace __msan { using namespace __sanitizer; } // NOLINT -namespace __hwasan { using namespace __sanitizer; } // NOLINT -namespace __tsan { using namespace __sanitizer; } // NOLINT -namespace __scudo { using namespace __sanitizer; } // NOLINT -namespace __ubsan { using namespace __sanitizer; } // NOLINT -namespace __xray { using namespace __sanitizer; } // NOLINT -namespace __interception { using namespace __sanitizer; } // NOLINT -namespace __hwasan { using namespace __sanitizer; } // NOLINT - +namespace __asan { +using namespace __sanitizer; +} +namespace __dsan { +using namespace __sanitizer; +} +namespace __dfsan { +using namespace __sanitizer; +} +namespace __lsan { +using namespace __sanitizer; +} +namespace __msan { +using namespace __sanitizer; +} +namespace __hwasan { +using namespace __sanitizer; +} +namespace __tsan { +using namespace __sanitizer; +} +namespace __scudo { +using namespace __sanitizer; +} +namespace __ubsan { +using namespace __sanitizer; +} +namespace __xray { +using namespace __sanitizer; +} +namespace __interception { +using namespace __sanitizer; +} +namespace __hwasan { +using namespace __sanitizer; +} #endif // SANITIZER_DEFS_H diff --git a/libsanitizer/sanitizer_common/sanitizer_libc.cpp b/libsanitizer/sanitizer_common/sanitizer_libc.cpp index 5c9d3a80c13..4bc04b48687 100644 --- a/libsanitizer/sanitizer_common/sanitizer_libc.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_libc.cpp @@ -63,10 +63,11 @@ void *internal_memmove(void *dest, const void *src, uptr n) { for (i = 0; i < signed_n; ++i) d[i] = s[i]; } else { - if (d > s && signed_n > 0) - for (i = signed_n - 1; i >= 0 ; --i) { + if (d > s && signed_n > 0) { + for (i = signed_n - 1; i >= 0; --i) { d[i] = s[i]; } + } } return dest; } @@ -270,9 +271,9 @@ bool mem_is_zero(const char *beg, uptr size) { for (; aligned_beg < aligned_end; aligned_beg++) all |= *aligned_beg; // Epilogue. - if ((char*)aligned_end >= beg) - for (const char *mem = (char*)aligned_end; mem < end; mem++) - all |= *mem; + if ((char *)aligned_end >= beg) { + for (const char *mem = (char *)aligned_end; mem < end; mem++) all |= *mem; + } return all == 0; } diff --git a/libsanitizer/sanitizer_common/sanitizer_linux.cpp b/libsanitizer/sanitizer_common/sanitizer_linux.cpp index 1ed6af33fb8..0b53da6c349 100644 --- a/libsanitizer/sanitizer_common/sanitizer_linux.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_linux.cpp @@ -1062,8 +1062,6 @@ uptr GetMaxUserVirtualAddress() { uptr GetPageSize() { #if SANITIZER_LINUX && (defined(__x86_64__) || defined(__i386__)) return EXEC_PAGESIZE; -#elif SANITIZER_USE_GETAUXVAL - return getauxval(AT_PAGESZ); #elif SANITIZER_FREEBSD || SANITIZER_NETBSD // Use sysctl as sysconf can trigger interceptors internally. int pz = 0; @@ -1072,6 +1070,8 @@ uptr GetPageSize() { int rv = internal_sysctl(mib, 2, &pz, &pzl, nullptr, 0); CHECK_EQ(rv, 0); return (uptr)pz; +#elif SANITIZER_USE_GETAUXVAL + return getauxval(AT_PAGESZ); #else return sysconf(_SC_PAGESIZE); // EXEC_PAGESIZE may not be trustworthy. #endif @@ -1849,6 +1849,12 @@ SignalContext::WriteFlag SignalContext::GetWriteFlag() const { #endif } +bool SignalContext::IsTrueFaultingAddress() const { + auto si = static_cast(siginfo); + // SIGSEGV signals without a true fault address have si_code set to 128. + return si->si_signo == SIGSEGV && si->si_code != 128; +} + void SignalContext::DumpAllRegisters(void *context) { // FIXME: Implement this. } @@ -2011,6 +2017,35 @@ void CheckASLR() { CHECK_NE(personality(old_personality | ADDR_NO_RANDOMIZE), -1); ReExec(); } +#elif SANITIZER_FREEBSD + int aslr_pie; + uptr len = sizeof(aslr_pie); +#if SANITIZER_WORDSIZE == 64 + if (UNLIKELY(internal_sysctlbyname("kern.elf64.aslr.pie_enable", + &aslr_pie, &len, NULL, 0) == -1)) { + // We're making things less 'dramatic' here since + // the OID is not necessarily guaranteed to be here + // just yet regarding FreeBSD release + return; + } + + if (aslr_pie > 0) { + Printf("This sanitizer is not compatible with enabled ASLR " + "and binaries compiled with PIE\n"); + Die(); + } +#endif + // there might be 32 bits compat for 64 bits + if (UNLIKELY(internal_sysctlbyname("kern.elf32.aslr.pie_enable", + &aslr_pie, &len, NULL, 0) == -1)) { + return; + } + + if (aslr_pie > 0) { + Printf("This sanitizer is not compatible with enabled ASLR " + "and binaries compiled with PIE\n"); + Die(); + } #else // Do nothing #endif diff --git a/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp index 7dc38a0b703..cd503718205 100644 --- a/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp @@ -23,6 +23,7 @@ #include "sanitizer_flags.h" #include "sanitizer_freebsd.h" #include "sanitizer_getauxval.h" +#include "sanitizer_glibc_version.h" #include "sanitizer_linux.h" #include "sanitizer_placement_new.h" #include "sanitizer_procmaps.h" @@ -188,11 +189,7 @@ __attribute__((unused)) static bool GetLibcVersion(int *major, int *minor, static uptr g_tls_size; #ifdef __i386__ -# ifndef __GLIBC_PREREQ -# define CHECK_GET_TLS_STATIC_INFO_VERSION 1 -# else -# define CHECK_GET_TLS_STATIC_INFO_VERSION (!__GLIBC_PREREQ(2, 27)) -# endif +# define CHECK_GET_TLS_STATIC_INFO_VERSION (!__GLIBC_PREREQ(2, 27)) #else # define CHECK_GET_TLS_STATIC_INFO_VERSION 0 #endif @@ -701,13 +698,9 @@ u32 GetNumberOfCPUs() { #elif SANITIZER_SOLARIS return sysconf(_SC_NPROCESSORS_ONLN); #else -#if defined(CPU_COUNT) cpu_set_t CPUs; CHECK_EQ(sched_getaffinity(0, sizeof(cpu_set_t), &CPUs), 0); return CPU_COUNT(&CPUs); -#else - return 1; -#endif #endif } diff --git a/libsanitizer/sanitizer_common/sanitizer_mac.cpp b/libsanitizer/sanitizer_common/sanitizer_mac.cpp index 7552b7aa965..ea4bd02aa92 100644 --- a/libsanitizer/sanitizer_common/sanitizer_mac.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_mac.cpp @@ -13,6 +13,7 @@ #include "sanitizer_platform.h" #if SANITIZER_MAC #include "sanitizer_mac.h" +#include "interception/interception.h" // Use 64-bit inodes in file operations. ASan does not support OS X 10.5, so // the clients will most certainly use 64-bit ones as well. @@ -36,7 +37,7 @@ extern char **environ; #endif -#if defined(__has_include) && __has_include() && defined(__BLOCKS__) +#if defined(__has_include) && __has_include() #define SANITIZER_OS_TRACE 1 #include #else @@ -64,7 +65,9 @@ extern "C" { #include #include #include +#include #include +#include #include #include #include @@ -239,27 +242,102 @@ int internal_sysctlbyname(const char *sname, void *oldp, uptr *oldlenp, (size_t)newlen); } -int internal_forkpty(int *aparent) { - int parent, worker; - if (openpty(&parent, &worker, nullptr, nullptr, nullptr) == -1) return -1; - int pid = internal_fork(); - if (pid == -1) { - close(parent); - close(worker); - return -1; +static fd_t internal_spawn_impl(const char *argv[], pid_t *pid) { + fd_t master_fd = kInvalidFd; + fd_t slave_fd = kInvalidFd; + + auto fd_closer = at_scope_exit([&] { + internal_close(master_fd); + internal_close(slave_fd); + }); + + // We need a new pseudoterminal to avoid buffering problems. The 'atos' tool + // in particular detects when it's talking to a pipe and forgets to flush the + // output stream after sending a response. + master_fd = posix_openpt(O_RDWR); + if (master_fd == kInvalidFd) return kInvalidFd; + + int res = grantpt(master_fd) || unlockpt(master_fd); + if (res != 0) return kInvalidFd; + + // Use TIOCPTYGNAME instead of ptsname() to avoid threading problems. + char slave_pty_name[128]; + res = ioctl(master_fd, TIOCPTYGNAME, slave_pty_name); + if (res == -1) return kInvalidFd; + + slave_fd = internal_open(slave_pty_name, O_RDWR); + if (slave_fd == kInvalidFd) return kInvalidFd; + + // File descriptor actions + posix_spawn_file_actions_t acts; + res = posix_spawn_file_actions_init(&acts); + if (res != 0) return kInvalidFd; + + auto acts_cleanup = at_scope_exit([&] { + posix_spawn_file_actions_destroy(&acts); + }); + + res = posix_spawn_file_actions_adddup2(&acts, slave_fd, STDIN_FILENO) || + posix_spawn_file_actions_adddup2(&acts, slave_fd, STDOUT_FILENO) || + posix_spawn_file_actions_addclose(&acts, slave_fd); + if (res != 0) return kInvalidFd; + + // Spawn attributes + posix_spawnattr_t attrs; + res = posix_spawnattr_init(&attrs); + if (res != 0) return kInvalidFd; + + auto attrs_cleanup = at_scope_exit([&] { + posix_spawnattr_destroy(&attrs); + }); + + // In the spawned process, close all file descriptors that are not explicitly + // described by the file actions object. This is Darwin-specific extension. + res = posix_spawnattr_setflags(&attrs, POSIX_SPAWN_CLOEXEC_DEFAULT); + if (res != 0) return kInvalidFd; + + // posix_spawn + char **argv_casted = const_cast(argv); + char **env = GetEnviron(); + res = posix_spawn(pid, argv[0], &acts, &attrs, argv_casted, env); + if (res != 0) return kInvalidFd; + + // Disable echo in the new terminal, disable CR. + struct termios termflags; + tcgetattr(master_fd, &termflags); + termflags.c_oflag &= ~ONLCR; + termflags.c_lflag &= ~ECHO; + tcsetattr(master_fd, TCSANOW, &termflags); + + // On success, do not close master_fd on scope exit. + fd_t fd = master_fd; + master_fd = kInvalidFd; + + return fd; +} + +fd_t internal_spawn(const char *argv[], pid_t *pid) { + // The client program may close its stdin and/or stdout and/or stderr thus + // allowing open/posix_openpt to reuse file descriptors 0, 1 or 2. In this + // case the communication is broken if either the parent or the child tries to + // close or duplicate these descriptors. We temporarily reserve these + // descriptors here to prevent this. + fd_t low_fds[3]; + size_t count = 0; + + for (; count < 3; count++) { + low_fds[count] = posix_openpt(O_RDWR); + if (low_fds[count] >= STDERR_FILENO) + break; } - if (pid == 0) { - close(parent); - if (login_tty(worker) != 0) { - // We already forked, there's not much we can do. Let's quit. - Report("login_tty failed (errno %d)\n", errno); - internal__exit(1); - } - } else { - *aparent = parent; - close(worker); + + fd_t fd = internal_spawn_impl(argv, pid); + + for (; count > 0; count--) { + internal_close(low_fds[count]); } - return pid; + + return fd; } uptr internal_rename(const char *oldpath, const char *newpath) { @@ -676,6 +754,12 @@ SignalContext::WriteFlag SignalContext::GetWriteFlag() const { #endif } +bool SignalContext::IsTrueFaultingAddress() const { + auto si = static_cast(siginfo); + // "Real" SIGSEGV codes (e.g., SEGV_MAPERR, SEGV_MAPERR) are non-zero. + return si->si_signo == SIGSEGV && si->si_code != 0; +} + static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { ucontext_t *ucontext = (ucontext_t*)context; # if defined(__aarch64__) @@ -1122,7 +1206,7 @@ bool GetRandom(void *buffer, uptr length, bool blocking) { if (!buffer || !length || length > 256) return false; // arc4random never fails. - arc4random_buf(buffer, length); + REAL(arc4random_buf)(buffer, length); return true; } diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h b/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h index e7becbb0e20..61a6b82ef81 100644 --- a/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h +++ b/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h @@ -13,6 +13,7 @@ #ifndef SANITIZER_PLATFORM_INTERCEPTORS_H #define SANITIZER_PLATFORM_INTERCEPTORS_H +#include "sanitizer_glibc_version.h" #include "sanitizer_internal_defs.h" #if SANITIZER_POSIX @@ -331,10 +332,9 @@ #define SANITIZER_INTERCEPT_ETHER_HOST \ (SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID) #define SANITIZER_INTERCEPT_ETHER_R (SI_FREEBSD || SI_LINUX_NOT_ANDROID) -#define SANITIZER_INTERCEPT_SHMCTL \ - (SI_NETBSD || SI_OPENBSD || SI_SOLARIS || \ - ((SI_FREEBSD || SI_LINUX_NOT_ANDROID) && \ - SANITIZER_WORDSIZE == 64)) // NOLINT +#define SANITIZER_INTERCEPT_SHMCTL \ + (((SI_FREEBSD || SI_LINUX_NOT_ANDROID) && SANITIZER_WORDSIZE == 64) || \ + SI_NETBSD || SI_OPENBSD || SI_SOLARIS) // NOLINT #define SANITIZER_INTERCEPT_RANDOM_R SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_PTHREAD_ATTR_GET SI_POSIX #define SANITIZER_INTERCEPT_PTHREAD_ATTR_GETINHERITSCHED \ @@ -489,7 +489,8 @@ SI_NOT_RTEMS) #define SANITIZER_INTERCEPT_REALLOCARRAY SI_POSIX #define SANITIZER_INTERCEPT_ALIGNED_ALLOC (!SI_MAC && SI_NOT_RTEMS) -#define SANITIZER_INTERCEPT_MALLOC_USABLE_SIZE (!SI_MAC && !SI_OPENBSD) +#define SANITIZER_INTERCEPT_MALLOC_USABLE_SIZE \ + (!SI_MAC && !SI_OPENBSD && !SI_NETBSD) #define SANITIZER_INTERCEPT_MCHECK_MPROBE SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_WCSCAT SI_POSIX #define SANITIZER_INTERCEPT_WCSDUP SI_POSIX @@ -561,11 +562,18 @@ #define SANITIZER_INTERCEPT_FUNOPEN (SI_NETBSD || SI_FREEBSD) #define SANITIZER_INTERCEPT_FUNOPEN2 SI_NETBSD #define SANITIZER_INTERCEPT_GETFSENT (SI_FREEBSD || SI_NETBSD || SI_MAC) -#define SANITIZER_INTERCEPT_ARC4RANDOM (SI_FREEBSD || SI_NETBSD) +#define SANITIZER_INTERCEPT_ARC4RANDOM (SI_FREEBSD || SI_NETBSD || SI_MAC) #define SANITIZER_INTERCEPT_FDEVNAME SI_FREEBSD #define SANITIZER_INTERCEPT_GETUSERSHELL (SI_POSIX && !SI_ANDROID) #define SANITIZER_INTERCEPT_SL_INIT (SI_FREEBSD || SI_NETBSD) - -#define SANITIZER_INTERCEPT_GETRANDOM SI_LINUX +#define SANITIZER_INTERCEPT_CRYPT (SI_POSIX && !SI_ANDROID) +#define SANITIZER_INTERCEPT_CRYPT_R (SI_LINUX && !SI_ANDROID) + +#define SANITIZER_INTERCEPT_GETRANDOM \ + ((SI_LINUX && __GLIBC_PREREQ(2, 25)) || SI_FREEBSD) +#define SANITIZER_INTERCEPT___CXA_ATEXIT SI_NETBSD +#define SANITIZER_INTERCEPT_ATEXIT SI_NETBSD +#define SANITIZER_INTERCEPT_PTHREAD_ATFORK SI_NETBSD +#define SANITIZER_INTERCEPT_GETENTROPY SI_FREEBSD #endif // #ifndef SANITIZER_PLATFORM_INTERCEPTORS_H diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.h b/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.h index 46307c6c434..71cf5b9c357 100644 --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.h +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.h @@ -30,373 +30,373 @@ #include namespace __sanitizer { - extern unsigned struct_utsname_sz; - extern unsigned struct_stat_sz; +extern unsigned struct_utsname_sz; +extern unsigned struct_stat_sz; #if defined(__powerpc64__) - const unsigned struct___old_kernel_stat_sz = 0; +const unsigned struct___old_kernel_stat_sz = 0; #else - const unsigned struct___old_kernel_stat_sz = 32; +const unsigned struct___old_kernel_stat_sz = 32; #endif - extern unsigned struct_rusage_sz; - extern unsigned siginfo_t_sz; - extern unsigned struct_itimerval_sz; - extern unsigned pthread_t_sz; - extern unsigned pthread_mutex_t_sz; - extern unsigned pthread_cond_t_sz; - extern unsigned pid_t_sz; - extern unsigned timeval_sz; - extern unsigned uid_t_sz; - extern unsigned gid_t_sz; - extern unsigned fpos_t_sz; - extern unsigned mbstate_t_sz; - extern unsigned struct_timezone_sz; - extern unsigned struct_tms_sz; - extern unsigned struct_itimerspec_sz; - extern unsigned struct_sigevent_sz; - extern unsigned struct_sched_param_sz; - extern unsigned struct_statfs64_sz; - extern unsigned struct_statfs_sz; - extern unsigned struct_sockaddr_sz; - extern unsigned ucontext_t_sz; - extern unsigned struct_rlimit_sz; - extern unsigned struct_utimbuf_sz; - extern unsigned struct_timespec_sz; - extern unsigned struct_regmatch_sz; - extern unsigned struct_regex_sz; - extern unsigned struct_FTS_sz; - extern unsigned struct_FTSENT_sz; - extern const int unvis_valid; - extern const int unvis_validpush; - - struct __sanitizer_iocb { - u64 aio_data; - u32 aio_key_or_aio_reserved1; // Simply crazy. - u32 aio_reserved1_or_aio_key; // Luckily, we don't need these. - u16 aio_lio_opcode; - s16 aio_reqprio; - u32 aio_fildes; - u64 aio_buf; - u64 aio_nbytes; - s64 aio_offset; - u64 aio_reserved2; - u64 aio_reserved3; - }; - - struct __sanitizer_io_event { - u64 data; - u64 obj; - u64 res; - u64 res2; - }; - - const unsigned iocb_cmd_pread = 0; - const unsigned iocb_cmd_pwrite = 1; - const unsigned iocb_cmd_preadv = 7; - const unsigned iocb_cmd_pwritev = 8; - - struct __sanitizer___sysctl_args { - int *name; - int nlen; - void *oldval; - uptr *oldlenp; - void *newval; - uptr newlen; - unsigned long ___unused[4]; - }; - - struct __sanitizer_ipc_perm { - unsigned int cuid; - unsigned int cgid; - unsigned int uid; - unsigned int gid; - unsigned short mode; - unsigned short seq; - long key; - }; - - struct __sanitizer_shmid_ds { - __sanitizer_ipc_perm shm_perm; - unsigned long shm_segsz; - unsigned int shm_lpid; - unsigned int shm_cpid; - int shm_nattch; - unsigned long shm_atime; - unsigned long shm_dtime; - unsigned long shm_ctime; - }; - - extern unsigned struct_msqid_ds_sz; - extern unsigned struct_mq_attr_sz; - extern unsigned struct_timeb_sz; - extern unsigned struct_statvfs_sz; - - struct __sanitizer_iovec { - void *iov_base; - uptr iov_len; - }; - - struct __sanitizer_ifaddrs { - struct __sanitizer_ifaddrs *ifa_next; - char *ifa_name; - unsigned int ifa_flags; - void *ifa_addr; // (struct sockaddr *) - void *ifa_netmask; // (struct sockaddr *) -# undef ifa_dstaddr - void *ifa_dstaddr; // (struct sockaddr *) - void *ifa_data; - }; - - typedef unsigned __sanitizer_pthread_key_t; - - struct __sanitizer_passwd { - char *pw_name; - char *pw_passwd; - int pw_uid; - int pw_gid; - long pw_change; - char *pw_class; - char *pw_gecos; - char *pw_dir; - char *pw_shell; - long pw_expire; - int pw_fields; - }; - - struct __sanitizer_group { - char *gr_name; - char *gr_passwd; - int gr_gid; - char **gr_mem; - }; - -#if defined(__LP64___) - typedef long long __sanitizer_time_t; +extern unsigned struct_rusage_sz; +extern unsigned siginfo_t_sz; +extern unsigned struct_itimerval_sz; +extern unsigned pthread_t_sz; +extern unsigned pthread_mutex_t_sz; +extern unsigned pthread_cond_t_sz; +extern unsigned pid_t_sz; +extern unsigned timeval_sz; +extern unsigned uid_t_sz; +extern unsigned gid_t_sz; +extern unsigned fpos_t_sz; +extern unsigned mbstate_t_sz; +extern unsigned struct_timezone_sz; +extern unsigned struct_tms_sz; +extern unsigned struct_itimerspec_sz; +extern unsigned struct_sigevent_sz; +extern unsigned struct_sched_param_sz; +extern unsigned struct_statfs64_sz; +extern unsigned struct_statfs_sz; +extern unsigned struct_sockaddr_sz; +extern unsigned ucontext_t_sz; +extern unsigned struct_rlimit_sz; +extern unsigned struct_utimbuf_sz; +extern unsigned struct_timespec_sz; +extern unsigned struct_regmatch_sz; +extern unsigned struct_regex_sz; +extern unsigned struct_FTS_sz; +extern unsigned struct_FTSENT_sz; +extern const int unvis_valid; +extern const int unvis_validpush; + +struct __sanitizer_iocb { + u64 aio_data; + u32 aio_key_or_aio_reserved1; // Simply crazy. + u32 aio_reserved1_or_aio_key; // Luckily, we don't need these. + u16 aio_lio_opcode; + s16 aio_reqprio; + u32 aio_fildes; + u64 aio_buf; + u64 aio_nbytes; + s64 aio_offset; + u64 aio_reserved2; + u64 aio_reserved3; +}; + +struct __sanitizer_io_event { + u64 data; + u64 obj; + u64 res; + u64 res2; +}; + +const unsigned iocb_cmd_pread = 0; +const unsigned iocb_cmd_pwrite = 1; +const unsigned iocb_cmd_preadv = 7; +const unsigned iocb_cmd_pwritev = 8; + +struct __sanitizer___sysctl_args { + int *name; + int nlen; + void *oldval; + uptr *oldlenp; + void *newval; + uptr newlen; + unsigned long ___unused[4]; +}; + +struct __sanitizer_ipc_perm { + unsigned int cuid; + unsigned int cgid; + unsigned int uid; + unsigned int gid; + unsigned short mode; + unsigned short seq; + long key; +}; + +#if !defined(__i386__) +typedef long long __sanitizer_time_t; #else - typedef long __sanitizer_time_t; +typedef long __sanitizer_time_t; #endif - typedef long __sanitizer_suseconds_t; - - struct __sanitizer_timeval { - __sanitizer_time_t tv_sec; - __sanitizer_suseconds_t tv_usec; - }; - - struct __sanitizer_itimerval { - struct __sanitizer_timeval it_interval; - struct __sanitizer_timeval it_value; - }; - - struct __sanitizer_timeb { - __sanitizer_time_t time; - unsigned short millitm; - short timezone; - short dstflag; - }; - - struct __sanitizer_ether_addr { - u8 octet[6]; - }; - - struct __sanitizer_tm { - int tm_sec; - int tm_min; - int tm_hour; - int tm_mday; - int tm_mon; - int tm_year; - int tm_wday; - int tm_yday; - int tm_isdst; - long int tm_gmtoff; - const char *tm_zone; - }; - - struct __sanitizer_msghdr { - void *msg_name; - unsigned msg_namelen; - struct __sanitizer_iovec *msg_iov; - unsigned msg_iovlen; - void *msg_control; - unsigned msg_controllen; - int msg_flags; - }; - - struct __sanitizer_cmsghdr { - unsigned cmsg_len; - int cmsg_level; - int cmsg_type; - }; - - struct __sanitizer_dirent { +struct __sanitizer_shmid_ds { + __sanitizer_ipc_perm shm_perm; + unsigned long shm_segsz; + unsigned int shm_lpid; + unsigned int shm_cpid; + int shm_nattch; + __sanitizer_time_t shm_atime; + __sanitizer_time_t shm_dtime; + __sanitizer_time_t shm_ctime; +}; + +extern unsigned struct_msqid_ds_sz; +extern unsigned struct_mq_attr_sz; +extern unsigned struct_timeb_sz; +extern unsigned struct_statvfs_sz; + +struct __sanitizer_iovec { + void *iov_base; + uptr iov_len; +}; + +struct __sanitizer_ifaddrs { + struct __sanitizer_ifaddrs *ifa_next; + char *ifa_name; + unsigned int ifa_flags; + void *ifa_addr; // (struct sockaddr *) + void *ifa_netmask; // (struct sockaddr *) +# undef ifa_dstaddr + void *ifa_dstaddr; // (struct sockaddr *) + void *ifa_data; +}; + +typedef unsigned __sanitizer_pthread_key_t; + +struct __sanitizer_passwd { + char *pw_name; + char *pw_passwd; + int pw_uid; + int pw_gid; + __sanitizer_time_t pw_change; + char *pw_class; + char *pw_gecos; + char *pw_dir; + char *pw_shell; + __sanitizer_time_t pw_expire; + int pw_fields; +}; + +struct __sanitizer_group { + char *gr_name; + char *gr_passwd; + int gr_gid; + char **gr_mem; +}; + +typedef long __sanitizer_suseconds_t; + +struct __sanitizer_timeval { + __sanitizer_time_t tv_sec; + __sanitizer_suseconds_t tv_usec; +}; + +struct __sanitizer_itimerval { + struct __sanitizer_timeval it_interval; + struct __sanitizer_timeval it_value; +}; + +struct __sanitizer_timeb { + __sanitizer_time_t time; + unsigned short millitm; + short timezone; + short dstflag; +}; + +struct __sanitizer_ether_addr { + u8 octet[6]; +}; + +struct __sanitizer_tm { + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; + long int tm_gmtoff; + const char *tm_zone; +}; + +struct __sanitizer_msghdr { + void *msg_name; + unsigned msg_namelen; + struct __sanitizer_iovec *msg_iov; + unsigned msg_iovlen; + void *msg_control; + unsigned msg_controllen; + int msg_flags; +}; + +struct __sanitizer_cmsghdr { + unsigned cmsg_len; + int cmsg_level; + int cmsg_type; +}; + +struct __sanitizer_dirent { #if defined(__INO64) - unsigned long long d_fileno; - unsigned long long d_off; + unsigned long long d_fileno; + unsigned long long d_off; #else - unsigned int d_fileno; + unsigned int d_fileno; #endif - unsigned short d_reclen; - // more fields that we don't care about - }; + unsigned short d_reclen; + // more fields that we don't care about +}; // 'clock_t' is 32 bits wide on x64 FreeBSD - typedef int __sanitizer_clock_t; - typedef int __sanitizer_clockid_t; +typedef int __sanitizer_clock_t; +typedef int __sanitizer_clockid_t; -#if defined(_LP64) || defined(__x86_64__) || defined(__powerpc__)\ - || defined(__mips__) - typedef unsigned __sanitizer___kernel_uid_t; - typedef unsigned __sanitizer___kernel_gid_t; +#if defined(_LP64) || defined(__x86_64__) || defined(__powerpc__) || \ + defined(__mips__) +typedef unsigned __sanitizer___kernel_uid_t; +typedef unsigned __sanitizer___kernel_gid_t; #else - typedef unsigned short __sanitizer___kernel_uid_t; - typedef unsigned short __sanitizer___kernel_gid_t; +typedef unsigned short __sanitizer___kernel_uid_t; +typedef unsigned short __sanitizer___kernel_gid_t; #endif - typedef long long __sanitizer___kernel_off_t; +typedef long long __sanitizer___kernel_off_t; #if defined(__powerpc__) || defined(__mips__) - typedef unsigned int __sanitizer___kernel_old_uid_t; - typedef unsigned int __sanitizer___kernel_old_gid_t; +typedef unsigned int __sanitizer___kernel_old_uid_t; +typedef unsigned int __sanitizer___kernel_old_gid_t; #else - typedef unsigned short __sanitizer___kernel_old_uid_t; - typedef unsigned short __sanitizer___kernel_old_gid_t; +typedef unsigned short __sanitizer___kernel_old_uid_t; +typedef unsigned short __sanitizer___kernel_old_gid_t; #endif - typedef long long __sanitizer___kernel_loff_t; - typedef struct { - unsigned long fds_bits[1024 / (8 * sizeof(long))]; - } __sanitizer___kernel_fd_set; - - // This thing depends on the platform. We are only interested in the upper - // limit. Verified with a compiler assert in .cpp. - const int pthread_attr_t_max_sz = 128; - union __sanitizer_pthread_attr_t { - char size[pthread_attr_t_max_sz]; // NOLINT - void *align; - }; - - const unsigned old_sigset_t_sz = sizeof(unsigned long); - - struct __sanitizer_sigset_t { - // uint32_t * 4 - unsigned int __bits[4]; - }; - - typedef __sanitizer_sigset_t __sanitizer_kernel_sigset_t; - - struct __sanitizer_siginfo { - // The size is determined by looking at sizeof of real siginfo_t on linux. - u64 opaque[128 / sizeof(u64)]; - }; - - using __sanitizer_sighandler_ptr = void (*)(int sig); - using __sanitizer_sigactionhandler_ptr = - void (*)(int sig, __sanitizer_siginfo *siginfo, void *uctx); - - struct __sanitizer_sigaction { - union { - __sanitizer_sigactionhandler_ptr sigaction; - __sanitizer_sighandler_ptr handler; - }; - int sa_flags; - __sanitizer_sigset_t sa_mask; - }; - - struct __sanitizer_sem_t { - u32 data[4]; - }; - - extern const uptr sig_ign; - extern const uptr sig_dfl; - extern const uptr sig_err; - extern const uptr sa_siginfo; - - extern int af_inet; - extern int af_inet6; - uptr __sanitizer_in_addr_sz(int af); - - struct __sanitizer_dl_phdr_info { - uptr dlpi_addr; - const char *dlpi_name; - const void *dlpi_phdr; - short dlpi_phnum; - }; - - extern unsigned struct_ElfW_Phdr_sz; - - struct __sanitizer_addrinfo { - int ai_flags; - int ai_family; - int ai_socktype; - int ai_protocol; - unsigned ai_addrlen; - char *ai_canonname; - void *ai_addr; - struct __sanitizer_addrinfo *ai_next; - }; - - struct __sanitizer_hostent { - char *h_name; - char **h_aliases; - int h_addrtype; - int h_length; - char **h_addr_list; - }; - - struct __sanitizer_pollfd { - int fd; - short events; - short revents; - }; - - typedef unsigned __sanitizer_nfds_t; - - struct __sanitizer_glob_t { - uptr gl_pathc; - uptr gl_matchc; - uptr gl_offs; - int gl_flags; - char **gl_pathv; - int (*gl_errfunc)(const char*, int); - void (*gl_closedir)(void *dirp); - struct dirent *(*gl_readdir)(void *dirp); - void *(*gl_opendir)(const char*); - int (*gl_lstat)(const char*, void* /* struct stat* */); - int (*gl_stat)(const char*, void* /* struct stat* */); - }; - - extern int glob_nomatch; - extern int glob_altdirfunc; - - extern unsigned path_max; - - struct __sanitizer_wordexp_t { - uptr we_wordc; - char **we_wordv; - uptr we_offs; - char *we_strings; - uptr we_nbytes; - }; - - 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; - - extern unsigned struct_utmpx_sz; - - extern int map_fixed; - - // ioctl arguments - struct __sanitizer_ifconf { - int ifc_len; - union { - void *ifcu_req; - } ifc_ifcu; +typedef long long __sanitizer___kernel_loff_t; +typedef struct { + unsigned long fds_bits[1024 / (8 * sizeof(long))]; +} __sanitizer___kernel_fd_set; + +// This thing depends on the platform. We are only interested in the upper +// limit. Verified with a compiler assert in .cpp. +union __sanitizer_pthread_attr_t { + char size[128]; + void *align; +}; + +const unsigned old_sigset_t_sz = sizeof(unsigned long); + +struct __sanitizer_sigset_t { + // uint32_t * 4 + unsigned int __bits[4]; +}; + +typedef __sanitizer_sigset_t __sanitizer_kernel_sigset_t; + +struct __sanitizer_siginfo { + // The size is determined by looking at sizeof of real siginfo_t on linux. + u64 opaque[128 / sizeof(u64)]; +}; + +using __sanitizer_sighandler_ptr = void (*)(int sig); +using __sanitizer_sigactionhandler_ptr = void (*)(int sig, + __sanitizer_siginfo *siginfo, + void *uctx); + +struct __sanitizer_sigaction { + union { + __sanitizer_sigactionhandler_ptr sigaction; + __sanitizer_sighandler_ptr handler; }; + int sa_flags; + __sanitizer_sigset_t sa_mask; +}; + +struct __sanitizer_sem_t { + u32 data[4]; +}; + +extern const uptr sig_ign; +extern const uptr sig_dfl; +extern const uptr sig_err; +extern const uptr sa_siginfo; + +extern int af_inet; +extern int af_inet6; +uptr __sanitizer_in_addr_sz(int af); + +struct __sanitizer_dl_phdr_info { + uptr dlpi_addr; + const char *dlpi_name; + const void *dlpi_phdr; + short dlpi_phnum; +}; + +extern unsigned struct_ElfW_Phdr_sz; + +struct __sanitizer_addrinfo { + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + unsigned ai_addrlen; + char *ai_canonname; + void *ai_addr; + struct __sanitizer_addrinfo *ai_next; +}; + +struct __sanitizer_hostent { + char *h_name; + char **h_aliases; + int h_addrtype; + int h_length; + char **h_addr_list; +}; + +struct __sanitizer_pollfd { + int fd; + short events; + short revents; +}; + +typedef unsigned __sanitizer_nfds_t; + +struct __sanitizer_glob_t { + uptr gl_pathc; + uptr gl_matchc; + uptr gl_offs; + int gl_flags; + char **gl_pathv; + int (*gl_errfunc)(const char *, int); + void (*gl_closedir)(void *dirp); + struct dirent *(*gl_readdir)(void *dirp); + void *(*gl_opendir)(const char *); + int (*gl_lstat)(const char *, void * /* struct stat* */); + int (*gl_stat)(const char *, void * /* struct stat* */); +}; + +extern int glob_nomatch; +extern int glob_altdirfunc; + +extern unsigned path_max; + +struct __sanitizer_wordexp_t { + uptr we_wordc; + char **we_wordv; + uptr we_offs; + char *we_strings; + uptr we_nbytes; +}; + +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; + +extern unsigned struct_utmpx_sz; + +extern int map_fixed; + +// ioctl arguments +struct __sanitizer_ifconf { + int ifc_len; + union { + void *ifcu_req; + } ifc_ifcu; +}; #define IOC_NRBITS 8 #define IOC_TYPEBITS 8 @@ -432,204 +432,204 @@ namespace __sanitizer { #define IOC_NR(nr) (((nr) >> IOC_NRSHIFT) & IOC_NRMASK) #define IOC_SIZE(nr) (((nr) >> IOC_SIZESHIFT) & IOC_SIZEMASK) - extern unsigned struct_ifreq_sz; - extern unsigned struct_termios_sz; - extern unsigned struct_winsize_sz; - - extern unsigned struct_copr_buffer_sz; - extern unsigned struct_copr_debug_buf_sz; - extern unsigned struct_copr_msg_sz; - extern unsigned struct_midi_info_sz; - extern unsigned struct_mtget_sz; - extern unsigned struct_mtop_sz; - extern unsigned struct_rtentry_sz; - extern unsigned struct_sbi_instrument_sz; - extern unsigned struct_seq_event_rec_sz; - extern unsigned struct_synth_info_sz; - extern unsigned struct_vt_mode_sz; - - extern const unsigned long __sanitizer_bufsiz; - extern unsigned struct_audio_buf_info_sz; - extern unsigned struct_ppp_stats_sz; - extern unsigned struct_sioc_sg_req_sz; - extern unsigned struct_sioc_vif_req_sz; - - // ioctl request identifiers - - // A special value to mark ioctls that are not present on the target platform, - // when it can not be determined without including any system headers. - extern const unsigned IOCTL_NOT_PRESENT; - - extern unsigned IOCTL_FIOASYNC; - extern unsigned IOCTL_FIOCLEX; - extern unsigned IOCTL_FIOGETOWN; - extern unsigned IOCTL_FIONBIO; - extern unsigned IOCTL_FIONCLEX; - extern unsigned IOCTL_FIOSETOWN; - extern unsigned IOCTL_SIOCADDMULTI; - extern unsigned IOCTL_SIOCATMARK; - extern unsigned IOCTL_SIOCDELMULTI; - extern unsigned IOCTL_SIOCGIFADDR; - extern unsigned IOCTL_SIOCGIFBRDADDR; - extern unsigned IOCTL_SIOCGIFCONF; - extern unsigned IOCTL_SIOCGIFDSTADDR; - extern unsigned IOCTL_SIOCGIFFLAGS; - extern unsigned IOCTL_SIOCGIFMETRIC; - extern unsigned IOCTL_SIOCGIFMTU; - extern unsigned IOCTL_SIOCGIFNETMASK; - extern unsigned IOCTL_SIOCGPGRP; - extern unsigned IOCTL_SIOCSIFADDR; - extern unsigned IOCTL_SIOCSIFBRDADDR; - extern unsigned IOCTL_SIOCSIFDSTADDR; - extern unsigned IOCTL_SIOCSIFFLAGS; - extern unsigned IOCTL_SIOCSIFMETRIC; - extern unsigned IOCTL_SIOCSIFMTU; - extern unsigned IOCTL_SIOCSIFNETMASK; - extern unsigned IOCTL_SIOCSPGRP; - extern unsigned IOCTL_TIOCCONS; - extern unsigned IOCTL_TIOCEXCL; - extern unsigned IOCTL_TIOCGETD; - extern unsigned IOCTL_TIOCGPGRP; - extern unsigned IOCTL_TIOCGWINSZ; - extern unsigned IOCTL_TIOCMBIC; - extern unsigned IOCTL_TIOCMBIS; - extern unsigned IOCTL_TIOCMGET; - extern unsigned IOCTL_TIOCMSET; - extern unsigned IOCTL_TIOCNOTTY; - extern unsigned IOCTL_TIOCNXCL; - extern unsigned IOCTL_TIOCOUTQ; - extern unsigned IOCTL_TIOCPKT; - extern unsigned IOCTL_TIOCSCTTY; - extern unsigned IOCTL_TIOCSETD; - extern unsigned IOCTL_TIOCSPGRP; - extern unsigned IOCTL_TIOCSTI; - extern unsigned IOCTL_TIOCSWINSZ; - extern unsigned IOCTL_SIOCGETSGCNT; - extern unsigned IOCTL_SIOCGETVIFCNT; - extern unsigned IOCTL_MTIOCGET; - extern unsigned IOCTL_MTIOCTOP; - extern unsigned IOCTL_SIOCADDRT; - extern unsigned IOCTL_SIOCDELRT; - extern unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE; - extern unsigned IOCTL_SNDCTL_DSP_GETFMTS; - extern unsigned IOCTL_SNDCTL_DSP_NONBLOCK; - extern unsigned IOCTL_SNDCTL_DSP_POST; - extern unsigned IOCTL_SNDCTL_DSP_RESET; - extern unsigned IOCTL_SNDCTL_DSP_SETFMT; - extern unsigned IOCTL_SNDCTL_DSP_SETFRAGMENT; - extern unsigned IOCTL_SNDCTL_DSP_SPEED; - extern unsigned IOCTL_SNDCTL_DSP_STEREO; - extern unsigned IOCTL_SNDCTL_DSP_SUBDIVIDE; - extern unsigned IOCTL_SNDCTL_DSP_SYNC; - extern unsigned IOCTL_SNDCTL_FM_4OP_ENABLE; - extern unsigned IOCTL_SNDCTL_FM_LOAD_INSTR; - extern unsigned IOCTL_SNDCTL_MIDI_INFO; - extern unsigned IOCTL_SNDCTL_MIDI_PRETIME; - extern unsigned IOCTL_SNDCTL_SEQ_CTRLRATE; - extern unsigned IOCTL_SNDCTL_SEQ_GETINCOUNT; - extern unsigned IOCTL_SNDCTL_SEQ_GETOUTCOUNT; - extern unsigned IOCTL_SNDCTL_SEQ_NRMIDIS; - extern unsigned IOCTL_SNDCTL_SEQ_NRSYNTHS; - extern unsigned IOCTL_SNDCTL_SEQ_OUTOFBAND; - extern unsigned IOCTL_SNDCTL_SEQ_PANIC; - extern unsigned IOCTL_SNDCTL_SEQ_PERCMODE; - extern unsigned IOCTL_SNDCTL_SEQ_RESET; - extern unsigned IOCTL_SNDCTL_SEQ_RESETSAMPLES; - extern unsigned IOCTL_SNDCTL_SEQ_SYNC; - extern unsigned IOCTL_SNDCTL_SEQ_TESTMIDI; - extern unsigned IOCTL_SNDCTL_SEQ_THRESHOLD; - extern unsigned IOCTL_SNDCTL_SYNTH_INFO; - extern unsigned IOCTL_SNDCTL_SYNTH_MEMAVL; - extern unsigned IOCTL_SNDCTL_TMR_CONTINUE; - extern unsigned IOCTL_SNDCTL_TMR_METRONOME; - extern unsigned IOCTL_SNDCTL_TMR_SELECT; - extern unsigned IOCTL_SNDCTL_TMR_SOURCE; - extern unsigned IOCTL_SNDCTL_TMR_START; - extern unsigned IOCTL_SNDCTL_TMR_STOP; - extern unsigned IOCTL_SNDCTL_TMR_TEMPO; - extern unsigned IOCTL_SNDCTL_TMR_TIMEBASE; - extern unsigned IOCTL_SOUND_MIXER_READ_ALTPCM; - extern unsigned IOCTL_SOUND_MIXER_READ_BASS; - extern unsigned IOCTL_SOUND_MIXER_READ_CAPS; - extern unsigned IOCTL_SOUND_MIXER_READ_CD; - extern unsigned IOCTL_SOUND_MIXER_READ_DEVMASK; - extern unsigned IOCTL_SOUND_MIXER_READ_ENHANCE; - extern unsigned IOCTL_SOUND_MIXER_READ_IGAIN; - extern unsigned IOCTL_SOUND_MIXER_READ_IMIX; - extern unsigned IOCTL_SOUND_MIXER_READ_LINE1; - extern unsigned IOCTL_SOUND_MIXER_READ_LINE2; - extern unsigned IOCTL_SOUND_MIXER_READ_LINE3; - extern unsigned IOCTL_SOUND_MIXER_READ_LINE; - extern unsigned IOCTL_SOUND_MIXER_READ_LOUD; - extern unsigned IOCTL_SOUND_MIXER_READ_MIC; - extern unsigned IOCTL_SOUND_MIXER_READ_MUTE; - extern unsigned IOCTL_SOUND_MIXER_READ_OGAIN; - extern unsigned IOCTL_SOUND_MIXER_READ_PCM; - extern unsigned IOCTL_SOUND_MIXER_READ_RECLEV; - extern unsigned IOCTL_SOUND_MIXER_READ_RECMASK; - extern unsigned IOCTL_SOUND_MIXER_READ_RECSRC; - extern unsigned IOCTL_SOUND_MIXER_READ_SPEAKER; - extern unsigned IOCTL_SOUND_MIXER_READ_STEREODEVS; - extern unsigned IOCTL_SOUND_MIXER_READ_SYNTH; - extern unsigned IOCTL_SOUND_MIXER_READ_TREBLE; - extern unsigned IOCTL_SOUND_MIXER_READ_VOLUME; - extern unsigned IOCTL_SOUND_MIXER_WRITE_ALTPCM; - extern unsigned IOCTL_SOUND_MIXER_WRITE_BASS; - extern unsigned IOCTL_SOUND_MIXER_WRITE_CD; - extern unsigned IOCTL_SOUND_MIXER_WRITE_ENHANCE; - extern unsigned IOCTL_SOUND_MIXER_WRITE_IGAIN; - extern unsigned IOCTL_SOUND_MIXER_WRITE_IMIX; - extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE1; - extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE2; - extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE3; - extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE; - extern unsigned IOCTL_SOUND_MIXER_WRITE_LOUD; - extern unsigned IOCTL_SOUND_MIXER_WRITE_MIC; - extern unsigned IOCTL_SOUND_MIXER_WRITE_MUTE; - extern unsigned IOCTL_SOUND_MIXER_WRITE_OGAIN; - extern unsigned IOCTL_SOUND_MIXER_WRITE_PCM; - extern unsigned IOCTL_SOUND_MIXER_WRITE_RECLEV; - extern unsigned IOCTL_SOUND_MIXER_WRITE_RECSRC; - extern unsigned IOCTL_SOUND_MIXER_WRITE_SPEAKER; - extern unsigned IOCTL_SOUND_MIXER_WRITE_SYNTH; - extern unsigned IOCTL_SOUND_MIXER_WRITE_TREBLE; - extern unsigned IOCTL_SOUND_MIXER_WRITE_VOLUME; - extern unsigned IOCTL_SOUND_PCM_READ_BITS; - extern unsigned IOCTL_SOUND_PCM_READ_CHANNELS; - extern unsigned IOCTL_SOUND_PCM_READ_FILTER; - extern unsigned IOCTL_SOUND_PCM_READ_RATE; - extern unsigned IOCTL_SOUND_PCM_WRITE_CHANNELS; - extern unsigned IOCTL_SOUND_PCM_WRITE_FILTER; - extern unsigned IOCTL_VT_ACTIVATE; - extern unsigned IOCTL_VT_GETMODE; - extern unsigned IOCTL_VT_OPENQRY; - extern unsigned IOCTL_VT_RELDISP; - extern unsigned IOCTL_VT_SETMODE; - extern unsigned IOCTL_VT_WAITACTIVE; - extern unsigned IOCTL_GIO_SCRNMAP; - extern unsigned IOCTL_KDDISABIO; - extern unsigned IOCTL_KDENABIO; - extern unsigned IOCTL_KDGETLED; - extern unsigned IOCTL_KDGETMODE; - extern unsigned IOCTL_KDGKBMODE; - extern unsigned IOCTL_KDGKBTYPE; - extern unsigned IOCTL_KDMKTONE; - extern unsigned IOCTL_KDSETLED; - extern unsigned IOCTL_KDSETMODE; - extern unsigned IOCTL_KDSKBMODE; - - extern const int si_SEGV_MAPERR; - extern const int si_SEGV_ACCERR; - - struct __sanitizer_cap_rights { - u64 cr_rights[2]; - }; - - typedef struct __sanitizer_cap_rights __sanitizer_cap_rights_t; - extern unsigned struct_cap_rights_sz; - - extern unsigned struct_fstab_sz; - extern unsigned struct_StringList_sz; +extern unsigned struct_ifreq_sz; +extern unsigned struct_termios_sz; +extern unsigned struct_winsize_sz; + +extern unsigned struct_copr_buffer_sz; +extern unsigned struct_copr_debug_buf_sz; +extern unsigned struct_copr_msg_sz; +extern unsigned struct_midi_info_sz; +extern unsigned struct_mtget_sz; +extern unsigned struct_mtop_sz; +extern unsigned struct_rtentry_sz; +extern unsigned struct_sbi_instrument_sz; +extern unsigned struct_seq_event_rec_sz; +extern unsigned struct_synth_info_sz; +extern unsigned struct_vt_mode_sz; + +extern const unsigned long __sanitizer_bufsiz; +extern unsigned struct_audio_buf_info_sz; +extern unsigned struct_ppp_stats_sz; +extern unsigned struct_sioc_sg_req_sz; +extern unsigned struct_sioc_vif_req_sz; + +// ioctl request identifiers + +// A special value to mark ioctls that are not present on the target platform, +// when it can not be determined without including any system headers. +extern const unsigned IOCTL_NOT_PRESENT; + +extern unsigned IOCTL_FIOASYNC; +extern unsigned IOCTL_FIOCLEX; +extern unsigned IOCTL_FIOGETOWN; +extern unsigned IOCTL_FIONBIO; +extern unsigned IOCTL_FIONCLEX; +extern unsigned IOCTL_FIOSETOWN; +extern unsigned IOCTL_SIOCADDMULTI; +extern unsigned IOCTL_SIOCATMARK; +extern unsigned IOCTL_SIOCDELMULTI; +extern unsigned IOCTL_SIOCGIFADDR; +extern unsigned IOCTL_SIOCGIFBRDADDR; +extern unsigned IOCTL_SIOCGIFCONF; +extern unsigned IOCTL_SIOCGIFDSTADDR; +extern unsigned IOCTL_SIOCGIFFLAGS; +extern unsigned IOCTL_SIOCGIFMETRIC; +extern unsigned IOCTL_SIOCGIFMTU; +extern unsigned IOCTL_SIOCGIFNETMASK; +extern unsigned IOCTL_SIOCGPGRP; +extern unsigned IOCTL_SIOCSIFADDR; +extern unsigned IOCTL_SIOCSIFBRDADDR; +extern unsigned IOCTL_SIOCSIFDSTADDR; +extern unsigned IOCTL_SIOCSIFFLAGS; +extern unsigned IOCTL_SIOCSIFMETRIC; +extern unsigned IOCTL_SIOCSIFMTU; +extern unsigned IOCTL_SIOCSIFNETMASK; +extern unsigned IOCTL_SIOCSPGRP; +extern unsigned IOCTL_TIOCCONS; +extern unsigned IOCTL_TIOCEXCL; +extern unsigned IOCTL_TIOCGETD; +extern unsigned IOCTL_TIOCGPGRP; +extern unsigned IOCTL_TIOCGWINSZ; +extern unsigned IOCTL_TIOCMBIC; +extern unsigned IOCTL_TIOCMBIS; +extern unsigned IOCTL_TIOCMGET; +extern unsigned IOCTL_TIOCMSET; +extern unsigned IOCTL_TIOCNOTTY; +extern unsigned IOCTL_TIOCNXCL; +extern unsigned IOCTL_TIOCOUTQ; +extern unsigned IOCTL_TIOCPKT; +extern unsigned IOCTL_TIOCSCTTY; +extern unsigned IOCTL_TIOCSETD; +extern unsigned IOCTL_TIOCSPGRP; +extern unsigned IOCTL_TIOCSTI; +extern unsigned IOCTL_TIOCSWINSZ; +extern unsigned IOCTL_SIOCGETSGCNT; +extern unsigned IOCTL_SIOCGETVIFCNT; +extern unsigned IOCTL_MTIOCGET; +extern unsigned IOCTL_MTIOCTOP; +extern unsigned IOCTL_SIOCADDRT; +extern unsigned IOCTL_SIOCDELRT; +extern unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE; +extern unsigned IOCTL_SNDCTL_DSP_GETFMTS; +extern unsigned IOCTL_SNDCTL_DSP_NONBLOCK; +extern unsigned IOCTL_SNDCTL_DSP_POST; +extern unsigned IOCTL_SNDCTL_DSP_RESET; +extern unsigned IOCTL_SNDCTL_DSP_SETFMT; +extern unsigned IOCTL_SNDCTL_DSP_SETFRAGMENT; +extern unsigned IOCTL_SNDCTL_DSP_SPEED; +extern unsigned IOCTL_SNDCTL_DSP_STEREO; +extern unsigned IOCTL_SNDCTL_DSP_SUBDIVIDE; +extern unsigned IOCTL_SNDCTL_DSP_SYNC; +extern unsigned IOCTL_SNDCTL_FM_4OP_ENABLE; +extern unsigned IOCTL_SNDCTL_FM_LOAD_INSTR; +extern unsigned IOCTL_SNDCTL_MIDI_INFO; +extern unsigned IOCTL_SNDCTL_MIDI_PRETIME; +extern unsigned IOCTL_SNDCTL_SEQ_CTRLRATE; +extern unsigned IOCTL_SNDCTL_SEQ_GETINCOUNT; +extern unsigned IOCTL_SNDCTL_SEQ_GETOUTCOUNT; +extern unsigned IOCTL_SNDCTL_SEQ_NRMIDIS; +extern unsigned IOCTL_SNDCTL_SEQ_NRSYNTHS; +extern unsigned IOCTL_SNDCTL_SEQ_OUTOFBAND; +extern unsigned IOCTL_SNDCTL_SEQ_PANIC; +extern unsigned IOCTL_SNDCTL_SEQ_PERCMODE; +extern unsigned IOCTL_SNDCTL_SEQ_RESET; +extern unsigned IOCTL_SNDCTL_SEQ_RESETSAMPLES; +extern unsigned IOCTL_SNDCTL_SEQ_SYNC; +extern unsigned IOCTL_SNDCTL_SEQ_TESTMIDI; +extern unsigned IOCTL_SNDCTL_SEQ_THRESHOLD; +extern unsigned IOCTL_SNDCTL_SYNTH_INFO; +extern unsigned IOCTL_SNDCTL_SYNTH_MEMAVL; +extern unsigned IOCTL_SNDCTL_TMR_CONTINUE; +extern unsigned IOCTL_SNDCTL_TMR_METRONOME; +extern unsigned IOCTL_SNDCTL_TMR_SELECT; +extern unsigned IOCTL_SNDCTL_TMR_SOURCE; +extern unsigned IOCTL_SNDCTL_TMR_START; +extern unsigned IOCTL_SNDCTL_TMR_STOP; +extern unsigned IOCTL_SNDCTL_TMR_TEMPO; +extern unsigned IOCTL_SNDCTL_TMR_TIMEBASE; +extern unsigned IOCTL_SOUND_MIXER_READ_ALTPCM; +extern unsigned IOCTL_SOUND_MIXER_READ_BASS; +extern unsigned IOCTL_SOUND_MIXER_READ_CAPS; +extern unsigned IOCTL_SOUND_MIXER_READ_CD; +extern unsigned IOCTL_SOUND_MIXER_READ_DEVMASK; +extern unsigned IOCTL_SOUND_MIXER_READ_ENHANCE; +extern unsigned IOCTL_SOUND_MIXER_READ_IGAIN; +extern unsigned IOCTL_SOUND_MIXER_READ_IMIX; +extern unsigned IOCTL_SOUND_MIXER_READ_LINE1; +extern unsigned IOCTL_SOUND_MIXER_READ_LINE2; +extern unsigned IOCTL_SOUND_MIXER_READ_LINE3; +extern unsigned IOCTL_SOUND_MIXER_READ_LINE; +extern unsigned IOCTL_SOUND_MIXER_READ_LOUD; +extern unsigned IOCTL_SOUND_MIXER_READ_MIC; +extern unsigned IOCTL_SOUND_MIXER_READ_MUTE; +extern unsigned IOCTL_SOUND_MIXER_READ_OGAIN; +extern unsigned IOCTL_SOUND_MIXER_READ_PCM; +extern unsigned IOCTL_SOUND_MIXER_READ_RECLEV; +extern unsigned IOCTL_SOUND_MIXER_READ_RECMASK; +extern unsigned IOCTL_SOUND_MIXER_READ_RECSRC; +extern unsigned IOCTL_SOUND_MIXER_READ_SPEAKER; +extern unsigned IOCTL_SOUND_MIXER_READ_STEREODEVS; +extern unsigned IOCTL_SOUND_MIXER_READ_SYNTH; +extern unsigned IOCTL_SOUND_MIXER_READ_TREBLE; +extern unsigned IOCTL_SOUND_MIXER_READ_VOLUME; +extern unsigned IOCTL_SOUND_MIXER_WRITE_ALTPCM; +extern unsigned IOCTL_SOUND_MIXER_WRITE_BASS; +extern unsigned IOCTL_SOUND_MIXER_WRITE_CD; +extern unsigned IOCTL_SOUND_MIXER_WRITE_ENHANCE; +extern unsigned IOCTL_SOUND_MIXER_WRITE_IGAIN; +extern unsigned IOCTL_SOUND_MIXER_WRITE_IMIX; +extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE1; +extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE2; +extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE3; +extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE; +extern unsigned IOCTL_SOUND_MIXER_WRITE_LOUD; +extern unsigned IOCTL_SOUND_MIXER_WRITE_MIC; +extern unsigned IOCTL_SOUND_MIXER_WRITE_MUTE; +extern unsigned IOCTL_SOUND_MIXER_WRITE_OGAIN; +extern unsigned IOCTL_SOUND_MIXER_WRITE_PCM; +extern unsigned IOCTL_SOUND_MIXER_WRITE_RECLEV; +extern unsigned IOCTL_SOUND_MIXER_WRITE_RECSRC; +extern unsigned IOCTL_SOUND_MIXER_WRITE_SPEAKER; +extern unsigned IOCTL_SOUND_MIXER_WRITE_SYNTH; +extern unsigned IOCTL_SOUND_MIXER_WRITE_TREBLE; +extern unsigned IOCTL_SOUND_MIXER_WRITE_VOLUME; +extern unsigned IOCTL_SOUND_PCM_READ_BITS; +extern unsigned IOCTL_SOUND_PCM_READ_CHANNELS; +extern unsigned IOCTL_SOUND_PCM_READ_FILTER; +extern unsigned IOCTL_SOUND_PCM_READ_RATE; +extern unsigned IOCTL_SOUND_PCM_WRITE_CHANNELS; +extern unsigned IOCTL_SOUND_PCM_WRITE_FILTER; +extern unsigned IOCTL_VT_ACTIVATE; +extern unsigned IOCTL_VT_GETMODE; +extern unsigned IOCTL_VT_OPENQRY; +extern unsigned IOCTL_VT_RELDISP; +extern unsigned IOCTL_VT_SETMODE; +extern unsigned IOCTL_VT_WAITACTIVE; +extern unsigned IOCTL_GIO_SCRNMAP; +extern unsigned IOCTL_KDDISABIO; +extern unsigned IOCTL_KDENABIO; +extern unsigned IOCTL_KDGETLED; +extern unsigned IOCTL_KDGETMODE; +extern unsigned IOCTL_KDGKBMODE; +extern unsigned IOCTL_KDGKBTYPE; +extern unsigned IOCTL_KDMKTONE; +extern unsigned IOCTL_KDSETLED; +extern unsigned IOCTL_KDSETMODE; +extern unsigned IOCTL_KDSKBMODE; + +extern const int si_SEGV_MAPERR; +extern const int si_SEGV_ACCERR; + +struct __sanitizer_cap_rights { + u64 cr_rights[2]; +}; + +typedef struct __sanitizer_cap_rights __sanitizer_cap_rights_t; +extern unsigned struct_cap_rights_sz; + +extern unsigned struct_fstab_sz; +extern unsigned struct_StringList_sz; } // namespace __sanitizer #define CHECK_TYPE_SIZE(TYPE) \ diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cpp b/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cpp index 7c1a21d6ccb..842bc789f47 100644 --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cpp @@ -26,12 +26,9 @@ // With old kernels (and even new kernels on powerpc) asm/stat.h uses types that // are not defined anywhere in userspace headers. Fake them. This seems to work -// fine with newer headers, too. Beware that with , struct stat -// takes the form of struct stat64 on 32-bit platforms if _FILE_OFFSET_BITS=64. -// Also, for some platforms (e.g. mips) there are additional members in the -// struct stat:s. +// fine with newer headers, too. #include -#if defined(__x86_64__) +#if defined(__x86_64__) || defined(__mips__) #include #else #define ino_t __kernel_ino_t diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp index 1e3c7feff8b..9852e6ba787 100644 --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp @@ -22,6 +22,10 @@ #ifdef _FILE_OFFSET_BITS #undef _FILE_OFFSET_BITS #endif + +// Must go after undef _FILE_OFFSET_BITS. +#include "sanitizer_glibc_version.h" + #include #include #include @@ -136,6 +140,7 @@ typedef struct user_fpregs elf_fpregset_t; #include #include #include +#include #endif // SANITIZER_LINUX && !SANITIZER_ANDROID #if SANITIZER_ANDROID @@ -236,6 +241,7 @@ namespace __sanitizer { unsigned struct_ustat_sz = SIZEOF_STRUCT_USTAT; unsigned struct_rlimit64_sz = sizeof(struct rlimit64); unsigned struct_statvfs64_sz = sizeof(struct statvfs64); + unsigned struct_crypt_data_sz = sizeof(struct crypt_data); #endif // SANITIZER_LINUX && !SANITIZER_ANDROID #if SANITIZER_LINUX && !SANITIZER_ANDROID @@ -1005,10 +1011,6 @@ CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_len); CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_level); CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_type); -#ifndef __GLIBC_PREREQ -#define __GLIBC_PREREQ(x, y) 0 -#endif - #if SANITIZER_LINUX && (__ANDROID_API__ >= 21 || __GLIBC_PREREQ (2, 14)) CHECK_TYPE_SIZE(mmsghdr); CHECK_SIZE_AND_OFFSET(mmsghdr, msg_hdr); @@ -1129,9 +1131,8 @@ CHECK_SIZE_AND_OFFSET(ipc_perm, cgid); #if (!defined(__aarch64__) || !SANITIZER_LINUX || __GLIBC_PREREQ (2, 21)) && \ !defined(__arm__) /* On aarch64 glibc 2.20 and earlier provided incorrect mode field. */ -/* On Arm glibc 2.31 and later provide a different mode field, this field is - never used by libsanitizer so we can simply ignore this assert for all glibc - versions. */ +/* On Arm newer glibc provide a different mode field, it's hard to detect + so just disable the check. */ CHECK_SIZE_AND_OFFSET(ipc_perm, mode); #endif diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h index f2d4812059b..db2c4f07b3a 100644 --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h @@ -19,844 +19,846 @@ #include "sanitizer_internal_defs.h" #include "sanitizer_platform.h" -# define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) ((link_map*)(handle)) - -#ifndef __GLIBC_PREREQ -#define __GLIBC_PREREQ(x, y) 0 +#if defined(__sparc__) +// FIXME: This can't be included from tsan which does not support sparc yet. +#include "sanitizer_glibc_version.h" #endif +# define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) ((link_map*)(handle)) + namespace __sanitizer { - extern unsigned struct_utsname_sz; - extern unsigned struct_stat_sz; +extern unsigned struct_utsname_sz; +extern unsigned struct_stat_sz; #if !SANITIZER_IOS - extern unsigned struct_stat64_sz; -#endif - extern unsigned struct_rusage_sz; - extern unsigned siginfo_t_sz; - extern unsigned struct_itimerval_sz; - extern unsigned pthread_t_sz; - extern unsigned pthread_mutex_t_sz; - extern unsigned pthread_cond_t_sz; - extern unsigned pid_t_sz; - extern unsigned timeval_sz; - extern unsigned uid_t_sz; - extern unsigned gid_t_sz; - extern unsigned mbstate_t_sz; - extern unsigned struct_timezone_sz; - extern unsigned struct_tms_sz; - extern unsigned struct_itimerspec_sz; - extern unsigned struct_sigevent_sz; - extern unsigned struct_sched_param_sz; - extern unsigned struct_statfs64_sz; - extern unsigned struct_regex_sz; - extern unsigned struct_regmatch_sz; +extern unsigned struct_stat64_sz; +#endif +extern unsigned struct_rusage_sz; +extern unsigned siginfo_t_sz; +extern unsigned struct_itimerval_sz; +extern unsigned pthread_t_sz; +extern unsigned pthread_mutex_t_sz; +extern unsigned pthread_cond_t_sz; +extern unsigned pid_t_sz; +extern unsigned timeval_sz; +extern unsigned uid_t_sz; +extern unsigned gid_t_sz; +extern unsigned mbstate_t_sz; +extern unsigned struct_timezone_sz; +extern unsigned struct_tms_sz; +extern unsigned struct_itimerspec_sz; +extern unsigned struct_sigevent_sz; +extern unsigned struct_sched_param_sz; +extern unsigned struct_statfs64_sz; +extern unsigned struct_regex_sz; +extern unsigned struct_regmatch_sz; #if !SANITIZER_ANDROID - extern unsigned struct_fstab_sz; - extern unsigned struct_statfs_sz; - extern unsigned struct_sockaddr_sz; - extern unsigned ucontext_t_sz; +extern unsigned struct_fstab_sz; +extern unsigned struct_statfs_sz; +extern unsigned struct_sockaddr_sz; +extern unsigned ucontext_t_sz; #endif // !SANITIZER_ANDROID #if SANITIZER_LINUX #if defined(__x86_64__) - const unsigned struct_kernel_stat_sz = 144; - const unsigned struct_kernel_stat64_sz = 0; +const unsigned struct_kernel_stat_sz = 144; +const unsigned struct_kernel_stat64_sz = 0; #elif defined(__i386__) - const unsigned struct_kernel_stat_sz = 64; - const unsigned struct_kernel_stat64_sz = 96; +const unsigned struct_kernel_stat_sz = 64; +const unsigned struct_kernel_stat64_sz = 96; #elif defined(__arm__) - const unsigned struct_kernel_stat_sz = 64; - const unsigned struct_kernel_stat64_sz = 104; +const unsigned struct_kernel_stat_sz = 64; +const unsigned struct_kernel_stat64_sz = 104; #elif defined(__aarch64__) - const unsigned struct_kernel_stat_sz = 128; - const unsigned struct_kernel_stat64_sz = 104; +const unsigned struct_kernel_stat_sz = 128; +const unsigned struct_kernel_stat64_sz = 104; #elif defined(__powerpc__) && !defined(__powerpc64__) - const unsigned struct_kernel_stat_sz = 72; - const unsigned struct_kernel_stat64_sz = 104; +const unsigned struct_kernel_stat_sz = 72; +const unsigned struct_kernel_stat64_sz = 104; #elif defined(__powerpc64__) - const unsigned struct_kernel_stat_sz = 144; - const unsigned struct_kernel_stat64_sz = 104; +const unsigned struct_kernel_stat_sz = 144; +const unsigned struct_kernel_stat64_sz = 104; #elif defined(__mips__) - const unsigned struct_kernel_stat_sz = - SANITIZER_ANDROID ? FIRST_32_SECOND_64(104, 128) : - FIRST_32_SECOND_64(144, 216); - const unsigned struct_kernel_stat64_sz = 104; +const unsigned struct_kernel_stat_sz = SANITIZER_ANDROID + ? FIRST_32_SECOND_64(104, 128) + : FIRST_32_SECOND_64(160, 216); +const unsigned struct_kernel_stat64_sz = 104; #elif defined(__s390__) && !defined(__s390x__) - const unsigned struct_kernel_stat_sz = 64; - const unsigned struct_kernel_stat64_sz = 104; +const unsigned struct_kernel_stat_sz = 64; +const unsigned struct_kernel_stat64_sz = 104; #elif defined(__s390x__) - const unsigned struct_kernel_stat_sz = 144; - const unsigned struct_kernel_stat64_sz = 0; +const unsigned struct_kernel_stat_sz = 144; +const unsigned struct_kernel_stat64_sz = 0; #elif defined(__sparc__) && defined(__arch64__) - const unsigned struct___old_kernel_stat_sz = 0; - const unsigned struct_kernel_stat_sz = 104; - const unsigned struct_kernel_stat64_sz = 144; +const unsigned struct___old_kernel_stat_sz = 0; +const unsigned struct_kernel_stat_sz = 104; +const unsigned struct_kernel_stat64_sz = 144; #elif defined(__sparc__) && !defined(__arch64__) - const unsigned struct___old_kernel_stat_sz = 0; - const unsigned struct_kernel_stat_sz = 64; - const unsigned struct_kernel_stat64_sz = 104; -#endif - struct __sanitizer_perf_event_attr { - unsigned type; - unsigned size; - // More fields that vary with the kernel version. - }; +const unsigned struct___old_kernel_stat_sz = 0; +const unsigned struct_kernel_stat_sz = 64; +const unsigned struct_kernel_stat64_sz = 104; +#endif +struct __sanitizer_perf_event_attr { + unsigned type; + unsigned size; + // More fields that vary with the kernel version. +}; - extern unsigned struct_epoll_event_sz; - extern unsigned struct_sysinfo_sz; - extern unsigned __user_cap_header_struct_sz; - extern unsigned __user_cap_data_struct_sz; - extern unsigned struct_new_utsname_sz; - extern unsigned struct_old_utsname_sz; - extern unsigned struct_oldold_utsname_sz; +extern unsigned struct_epoll_event_sz; +extern unsigned struct_sysinfo_sz; +extern unsigned __user_cap_header_struct_sz; +extern unsigned __user_cap_data_struct_sz; +extern unsigned struct_new_utsname_sz; +extern unsigned struct_old_utsname_sz; +extern unsigned struct_oldold_utsname_sz; - const unsigned struct_kexec_segment_sz = 4 * sizeof(unsigned long); +const unsigned struct_kexec_segment_sz = 4 * sizeof(unsigned long); #endif // SANITIZER_LINUX #if SANITIZER_LINUX #if defined(__powerpc64__) || defined(__s390__) - const unsigned struct___old_kernel_stat_sz = 0; +const unsigned struct___old_kernel_stat_sz = 0; #elif !defined(__sparc__) - const unsigned struct___old_kernel_stat_sz = 32; -#endif - - extern unsigned struct_rlimit_sz; - extern unsigned struct_utimbuf_sz; - extern unsigned struct_timespec_sz; - - struct __sanitizer_iocb { - u64 aio_data; - u32 aio_key_or_aio_reserved1; // Simply crazy. - u32 aio_reserved1_or_aio_key; // Luckily, we don't need these. - u16 aio_lio_opcode; - s16 aio_reqprio; - u32 aio_fildes; - u64 aio_buf; - u64 aio_nbytes; - s64 aio_offset; - u64 aio_reserved2; - u64 aio_reserved3; - }; +const unsigned struct___old_kernel_stat_sz = 32; +#endif - struct __sanitizer_io_event { - u64 data; - u64 obj; - u64 res; - u64 res2; - }; +extern unsigned struct_rlimit_sz; +extern unsigned struct_utimbuf_sz; +extern unsigned struct_timespec_sz; + +struct __sanitizer_iocb { + u64 aio_data; + u32 aio_key_or_aio_reserved1; // Simply crazy. + u32 aio_reserved1_or_aio_key; // Luckily, we don't need these. + u16 aio_lio_opcode; + s16 aio_reqprio; + u32 aio_fildes; + u64 aio_buf; + u64 aio_nbytes; + s64 aio_offset; + u64 aio_reserved2; + u64 aio_reserved3; +}; - const unsigned iocb_cmd_pread = 0; - const unsigned iocb_cmd_pwrite = 1; - const unsigned iocb_cmd_preadv = 7; - const unsigned iocb_cmd_pwritev = 8; - - struct __sanitizer___sysctl_args { - int *name; - int nlen; - void *oldval; - uptr *oldlenp; - void *newval; - uptr newlen; - unsigned long ___unused[4]; - }; +struct __sanitizer_io_event { + u64 data; + u64 obj; + u64 res; + u64 res2; +}; - const unsigned old_sigset_t_sz = sizeof(unsigned long); +const unsigned iocb_cmd_pread = 0; +const unsigned iocb_cmd_pwrite = 1; +const unsigned iocb_cmd_preadv = 7; +const unsigned iocb_cmd_pwritev = 8; + +struct __sanitizer___sysctl_args { + int *name; + int nlen; + void *oldval; + uptr *oldlenp; + void *newval; + uptr newlen; + unsigned long ___unused[4]; +}; - struct __sanitizer_sem_t { +const unsigned old_sigset_t_sz = sizeof(unsigned long); + +struct __sanitizer_sem_t { #if SANITIZER_ANDROID && defined(_LP64) - int data[4]; + int data[4]; #elif SANITIZER_ANDROID && !defined(_LP64) - int data; + int data; #elif SANITIZER_LINUX - uptr data[4]; + uptr data[4]; #endif - }; +}; #endif // SANITIZER_LINUX #if SANITIZER_ANDROID - struct __sanitizer_struct_mallinfo { - uptr v[10]; - }; +struct __sanitizer_struct_mallinfo { + uptr v[10]; +}; #endif #if SANITIZER_LINUX && !SANITIZER_ANDROID - struct __sanitizer_struct_mallinfo { - int v[10]; - }; +struct __sanitizer_struct_mallinfo { + int v[10]; +}; - extern unsigned struct_ustat_sz; - extern unsigned struct_rlimit64_sz; - extern unsigned struct_statvfs64_sz; +extern unsigned struct_ustat_sz; +extern unsigned struct_rlimit64_sz; +extern unsigned struct_statvfs64_sz; - struct __sanitizer_ipc_perm { - int __key; - int uid; - int gid; - int cuid; - int cgid; +struct __sanitizer_ipc_perm { + int __key; + int uid; + int gid; + int cuid; + int cgid; #ifdef __powerpc__ - unsigned mode; - unsigned __seq; - u64 __unused1; - u64 __unused2; + unsigned mode; + unsigned __seq; + u64 __unused1; + u64 __unused2; #elif defined(__sparc__) #if defined(__arch64__) - unsigned mode; - unsigned short __pad1; + unsigned mode; + unsigned short __pad1; #else - unsigned short __pad1; - unsigned short mode; - unsigned short __pad2; + unsigned short __pad1; + unsigned short mode; + unsigned short __pad2; #endif - unsigned short __seq; - unsigned long long __unused1; - unsigned long long __unused2; + unsigned short __seq; + unsigned long long __unused1; + unsigned long long __unused2; #elif defined(__mips__) || defined(__aarch64__) || defined(__s390x__) - unsigned int mode; - unsigned short __seq; - unsigned short __pad1; - unsigned long __unused1; - unsigned long __unused2; + unsigned int mode; + unsigned short __seq; + unsigned short __pad1; + unsigned long __unused1; + unsigned long __unused2; #else - unsigned short mode; - unsigned short __pad1; - unsigned short __seq; - unsigned short __pad2; + unsigned short mode; + unsigned short __pad1; + unsigned short __seq; + unsigned short __pad2; #if defined(__x86_64__) && !defined(_LP64) - u64 __unused1; - u64 __unused2; + u64 __unused1; + u64 __unused2; #else - unsigned long __unused1; - unsigned long __unused2; + unsigned long __unused1; + unsigned long __unused2; #endif #endif - }; +}; - struct __sanitizer_shmid_ds { - __sanitizer_ipc_perm shm_perm; - #if defined(__sparc__) - #if !defined(__arch64__) - u32 __pad1; - #endif - long shm_atime; - #if !defined(__arch64__) - u32 __pad2; - #endif - long shm_dtime; - #if !defined(__arch64__) - u32 __pad3; - #endif - long shm_ctime; - uptr shm_segsz; - int shm_cpid; - int shm_lpid; - unsigned long shm_nattch; - unsigned long __glibc_reserved1; - unsigned long __glibc_reserved2; - #else - #ifndef __powerpc__ - uptr shm_segsz; - #elif !defined(__powerpc64__) - uptr __unused0; - #endif - #if defined(__x86_64__) && !defined(_LP64) - u64 shm_atime; - u64 shm_dtime; - u64 shm_ctime; - #else - uptr shm_atime; - #if !defined(_LP64) && !defined(__mips__) - uptr __unused1; - #endif - uptr shm_dtime; - #if !defined(_LP64) && !defined(__mips__) - uptr __unused2; - #endif - uptr shm_ctime; - #if !defined(_LP64) && !defined(__mips__) - uptr __unused3; - #endif - #endif - #ifdef __powerpc__ - uptr shm_segsz; - #endif - int shm_cpid; - int shm_lpid; - #if defined(__x86_64__) && !defined(_LP64) - u64 shm_nattch; - u64 __unused4; - u64 __unused5; - #else - uptr shm_nattch; - uptr __unused4; - uptr __unused5; - #endif +struct __sanitizer_shmid_ds { + __sanitizer_ipc_perm shm_perm; +#if defined(__sparc__) +#if !defined(__arch64__) + u32 __pad1; #endif - }; + long shm_atime; +#if !defined(__arch64__) + u32 __pad2; +#endif + long shm_dtime; +#if !defined(__arch64__) + u32 __pad3; +#endif + long shm_ctime; + uptr shm_segsz; + int shm_cpid; + int shm_lpid; + unsigned long shm_nattch; + unsigned long __glibc_reserved1; + unsigned long __glibc_reserved2; +#else +#ifndef __powerpc__ + uptr shm_segsz; +#elif !defined(__powerpc64__) + uptr __unused0; +#endif +#if defined(__x86_64__) && !defined(_LP64) + u64 shm_atime; + u64 shm_dtime; + u64 shm_ctime; +#else + uptr shm_atime; +#if !defined(_LP64) && !defined(__mips__) + uptr __unused1; +#endif + uptr shm_dtime; +#if !defined(_LP64) && !defined(__mips__) + uptr __unused2; +#endif + uptr shm_ctime; +#if !defined(_LP64) && !defined(__mips__) + uptr __unused3; +#endif +#endif +#ifdef __powerpc__ + uptr shm_segsz; +#endif + int shm_cpid; + int shm_lpid; +#if defined(__x86_64__) && !defined(_LP64) + u64 shm_nattch; + u64 __unused4; + u64 __unused5; +#else + uptr shm_nattch; + uptr __unused4; + uptr __unused5; +#endif +#endif +}; #endif #if SANITIZER_LINUX && !SANITIZER_ANDROID - extern unsigned struct_msqid_ds_sz; - extern unsigned struct_mq_attr_sz; - extern unsigned struct_timex_sz; - extern unsigned struct_statvfs_sz; +extern unsigned struct_msqid_ds_sz; +extern unsigned struct_mq_attr_sz; +extern unsigned struct_timex_sz; +extern unsigned struct_statvfs_sz; +extern unsigned struct_crypt_data_sz; #endif // SANITIZER_LINUX && !SANITIZER_ANDROID - struct __sanitizer_iovec { - void *iov_base; - uptr iov_len; - }; +struct __sanitizer_iovec { + void *iov_base; + uptr iov_len; +}; #if !SANITIZER_ANDROID - struct __sanitizer_ifaddrs { - struct __sanitizer_ifaddrs *ifa_next; - char *ifa_name; - unsigned int ifa_flags; - void *ifa_addr; // (struct sockaddr *) - void *ifa_netmask; // (struct sockaddr *) - // This is a union on Linux. +struct __sanitizer_ifaddrs { + struct __sanitizer_ifaddrs *ifa_next; + char *ifa_name; + unsigned int ifa_flags; + void *ifa_addr; // (struct sockaddr *) + void *ifa_netmask; // (struct sockaddr *) + // This is a union on Linux. # ifdef ifa_dstaddr # undef ifa_dstaddr # endif - void *ifa_dstaddr; // (struct sockaddr *) - void *ifa_data; - }; + void *ifa_dstaddr; // (struct sockaddr *) + void *ifa_data; +}; #endif // !SANITIZER_ANDROID #if SANITIZER_MAC - typedef unsigned long __sanitizer_pthread_key_t; +typedef unsigned long __sanitizer_pthread_key_t; #else - typedef unsigned __sanitizer_pthread_key_t; +typedef unsigned __sanitizer_pthread_key_t; #endif #if SANITIZER_LINUX && !SANITIZER_ANDROID - struct __sanitizer_XDR { - int x_op; - void *x_ops; - uptr x_public; - uptr x_private; - uptr x_base; - unsigned x_handy; - }; +struct __sanitizer_XDR { + int x_op; + void *x_ops; + uptr x_public; + uptr x_private; + uptr x_base; + unsigned x_handy; +}; - const int __sanitizer_XDR_ENCODE = 0; - const int __sanitizer_XDR_DECODE = 1; - const int __sanitizer_XDR_FREE = 2; +const int __sanitizer_XDR_ENCODE = 0; +const int __sanitizer_XDR_DECODE = 1; +const int __sanitizer_XDR_FREE = 2; #endif - struct __sanitizer_passwd { - char *pw_name; - char *pw_passwd; - int pw_uid; - int pw_gid; +struct __sanitizer_passwd { + char *pw_name; + char *pw_passwd; + int pw_uid; + int pw_gid; #if SANITIZER_MAC - long pw_change; - char *pw_class; + long pw_change; + char *pw_class; #endif #if !(SANITIZER_ANDROID && (SANITIZER_WORDSIZE == 32)) - char *pw_gecos; + char *pw_gecos; #endif - char *pw_dir; - char *pw_shell; + char *pw_dir; + char *pw_shell; #if SANITIZER_MAC - long pw_expire; + long pw_expire; #endif - }; +}; - struct __sanitizer_group { - char *gr_name; - char *gr_passwd; - int gr_gid; - char **gr_mem; - }; +struct __sanitizer_group { + char *gr_name; + char *gr_passwd; + int gr_gid; + char **gr_mem; +}; #if defined(__x86_64__) && !defined(_LP64) - typedef long long __sanitizer_time_t; +typedef long long __sanitizer_time_t; #else - typedef long __sanitizer_time_t; +typedef long __sanitizer_time_t; #endif - typedef long __sanitizer_suseconds_t; +typedef long __sanitizer_suseconds_t; - struct __sanitizer_timeval { - __sanitizer_time_t tv_sec; - __sanitizer_suseconds_t tv_usec; - }; +struct __sanitizer_timeval { + __sanitizer_time_t tv_sec; + __sanitizer_suseconds_t tv_usec; +}; - struct __sanitizer_itimerval { - struct __sanitizer_timeval it_interval; - struct __sanitizer_timeval it_value; - }; +struct __sanitizer_itimerval { + struct __sanitizer_timeval it_interval; + struct __sanitizer_timeval it_value; +}; - struct __sanitizer_timeb { - __sanitizer_time_t time; - unsigned short millitm; - short timezone; - short dstflag; - }; +struct __sanitizer_timeb { + __sanitizer_time_t time; + unsigned short millitm; + short timezone; + short dstflag; +}; - struct __sanitizer_ether_addr { - u8 octet[6]; - }; +struct __sanitizer_ether_addr { + u8 octet[6]; +}; - struct __sanitizer_tm { - int tm_sec; - int tm_min; - int tm_hour; - int tm_mday; - int tm_mon; - int tm_year; - int tm_wday; - int tm_yday; - int tm_isdst; - long int tm_gmtoff; - const char *tm_zone; - }; +struct __sanitizer_tm { + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; + long int tm_gmtoff; + const char *tm_zone; +}; #if SANITIZER_LINUX - struct __sanitizer_mntent { - char *mnt_fsname; - char *mnt_dir; - char *mnt_type; - char *mnt_opts; - int mnt_freq; - int mnt_passno; - }; +struct __sanitizer_mntent { + char *mnt_fsname; + char *mnt_dir; + char *mnt_type; + char *mnt_opts; + int mnt_freq; + int mnt_passno; +}; - struct __sanitizer_file_handle { - unsigned int handle_bytes; - int handle_type; - unsigned char f_handle[1]; // variable sized - }; +struct __sanitizer_file_handle { + unsigned int handle_bytes; + int handle_type; + unsigned char f_handle[1]; // variable sized +}; #endif #if SANITIZER_MAC - struct __sanitizer_msghdr { - void *msg_name; - unsigned msg_namelen; - struct __sanitizer_iovec *msg_iov; - unsigned msg_iovlen; - void *msg_control; - unsigned msg_controllen; - int msg_flags; - }; - struct __sanitizer_cmsghdr { - unsigned cmsg_len; - int cmsg_level; - int cmsg_type; - }; +struct __sanitizer_msghdr { + void *msg_name; + unsigned msg_namelen; + struct __sanitizer_iovec *msg_iov; + unsigned msg_iovlen; + void *msg_control; + unsigned msg_controllen; + int msg_flags; +}; +struct __sanitizer_cmsghdr { + unsigned cmsg_len; + int cmsg_level; + int cmsg_type; +}; #else - struct __sanitizer_msghdr { - void *msg_name; - unsigned msg_namelen; - struct __sanitizer_iovec *msg_iov; - uptr msg_iovlen; - void *msg_control; - uptr msg_controllen; - int msg_flags; - }; - struct __sanitizer_cmsghdr { - uptr cmsg_len; - int cmsg_level; - int cmsg_type; - }; +struct __sanitizer_msghdr { + void *msg_name; + unsigned msg_namelen; + struct __sanitizer_iovec *msg_iov; + uptr msg_iovlen; + void *msg_control; + uptr msg_controllen; + int msg_flags; +}; +struct __sanitizer_cmsghdr { + uptr cmsg_len; + int cmsg_level; + int cmsg_type; +}; #endif #if SANITIZER_LINUX - struct __sanitizer_mmsghdr { - __sanitizer_msghdr msg_hdr; - unsigned int msg_len; - }; +struct __sanitizer_mmsghdr { + __sanitizer_msghdr msg_hdr; + unsigned int msg_len; +}; #endif #if SANITIZER_MAC - struct __sanitizer_dirent { - unsigned long long d_ino; - unsigned long long d_seekoff; - unsigned short d_reclen; - // more fields that we don't care about - }; +struct __sanitizer_dirent { + unsigned long long d_ino; + unsigned long long d_seekoff; + unsigned short d_reclen; + // more fields that we don't care about +}; #elif SANITIZER_ANDROID || defined(__x86_64__) - struct __sanitizer_dirent { - unsigned long long d_ino; - unsigned long long d_off; - unsigned short d_reclen; - // more fields that we don't care about - }; +struct __sanitizer_dirent { + unsigned long long d_ino; + unsigned long long d_off; + unsigned short d_reclen; + // more fields that we don't care about +}; #else - struct __sanitizer_dirent { - uptr d_ino; - uptr d_off; - unsigned short d_reclen; - // more fields that we don't care about - }; +struct __sanitizer_dirent { + uptr d_ino; + uptr d_off; + unsigned short d_reclen; + // more fields that we don't care about +}; #endif #if SANITIZER_LINUX && !SANITIZER_ANDROID - struct __sanitizer_dirent64 { - unsigned long long d_ino; - unsigned long long d_off; - unsigned short d_reclen; - // more fields that we don't care about - }; +struct __sanitizer_dirent64 { + unsigned long long d_ino; + unsigned long long d_off; + unsigned short d_reclen; + // more fields that we don't care about +}; #endif #if defined(__x86_64__) && !defined(_LP64) - typedef long long __sanitizer_clock_t; +typedef long long __sanitizer_clock_t; #else - typedef long __sanitizer_clock_t; +typedef long __sanitizer_clock_t; #endif #if SANITIZER_LINUX - typedef int __sanitizer_clockid_t; +typedef int __sanitizer_clockid_t; #endif #if SANITIZER_LINUX -#if defined(_LP64) || defined(__x86_64__) || defined(__powerpc__)\ - || defined(__mips__) - typedef unsigned __sanitizer___kernel_uid_t; - typedef unsigned __sanitizer___kernel_gid_t; +#if defined(_LP64) || defined(__x86_64__) || defined(__powerpc__) || \ + defined(__mips__) +typedef unsigned __sanitizer___kernel_uid_t; +typedef unsigned __sanitizer___kernel_gid_t; #else - typedef unsigned short __sanitizer___kernel_uid_t; - typedef unsigned short __sanitizer___kernel_gid_t; +typedef unsigned short __sanitizer___kernel_uid_t; +typedef unsigned short __sanitizer___kernel_gid_t; #endif #if defined(__x86_64__) && !defined(_LP64) - typedef long long __sanitizer___kernel_off_t; +typedef long long __sanitizer___kernel_off_t; #else - typedef long __sanitizer___kernel_off_t; +typedef long __sanitizer___kernel_off_t; #endif #if defined(__powerpc__) || defined(__mips__) - typedef unsigned int __sanitizer___kernel_old_uid_t; - typedef unsigned int __sanitizer___kernel_old_gid_t; +typedef unsigned int __sanitizer___kernel_old_uid_t; +typedef unsigned int __sanitizer___kernel_old_gid_t; #else - typedef unsigned short __sanitizer___kernel_old_uid_t; - typedef unsigned short __sanitizer___kernel_old_gid_t; +typedef unsigned short __sanitizer___kernel_old_uid_t; +typedef unsigned short __sanitizer___kernel_old_gid_t; #endif - typedef long long __sanitizer___kernel_loff_t; - typedef struct { - unsigned long fds_bits[1024 / (8 * sizeof(long))]; - } __sanitizer___kernel_fd_set; +typedef long long __sanitizer___kernel_loff_t; +typedef struct { + unsigned long fds_bits[1024 / (8 * sizeof(long))]; +} __sanitizer___kernel_fd_set; #endif - // This thing depends on the platform. We are only interested in the upper - // limit. Verified with a compiler assert in .cpp. - const int pthread_attr_t_max_sz = 128; - union __sanitizer_pthread_attr_t { - char size[pthread_attr_t_max_sz]; // NOLINT - void *align; - }; +// This thing depends on the platform. We are only interested in the upper +// limit. Verified with a compiler assert in .cpp. +union __sanitizer_pthread_attr_t { + char size[128]; + void *align; +}; #if SANITIZER_ANDROID # if SANITIZER_MIPS - typedef unsigned long __sanitizer_sigset_t[16/sizeof(unsigned long)]; +typedef unsigned long __sanitizer_sigset_t[16 / sizeof(unsigned long)]; # else - typedef unsigned long __sanitizer_sigset_t; +typedef unsigned long __sanitizer_sigset_t; # endif #elif SANITIZER_MAC - typedef unsigned __sanitizer_sigset_t; +typedef unsigned __sanitizer_sigset_t; #elif SANITIZER_LINUX - struct __sanitizer_sigset_t { - // The size is determined by looking at sizeof of real sigset_t on linux. - uptr val[128 / sizeof(uptr)]; - }; +struct __sanitizer_sigset_t { + // The size is determined by looking at sizeof of real sigset_t on linux. + uptr val[128 / sizeof(uptr)]; +}; #endif - struct __sanitizer_siginfo { - // The size is determined by looking at sizeof of real siginfo_t on linux. - u64 opaque[128 / sizeof(u64)]; - }; +struct __sanitizer_siginfo { + // The size is determined by looking at sizeof of real siginfo_t on linux. + u64 opaque[128 / sizeof(u64)]; +}; - using __sanitizer_sighandler_ptr = void (*)(int sig); - using __sanitizer_sigactionhandler_ptr = - void (*)(int sig, __sanitizer_siginfo *siginfo, void *uctx); +using __sanitizer_sighandler_ptr = void (*)(int sig); +using __sanitizer_sigactionhandler_ptr = void (*)(int sig, + __sanitizer_siginfo *siginfo, + void *uctx); - // Linux system headers define the 'sa_handler' and 'sa_sigaction' macros. +// Linux system headers define the 'sa_handler' and 'sa_sigaction' macros. #if SANITIZER_ANDROID && (SANITIZER_WORDSIZE == 64) - struct __sanitizer_sigaction { - unsigned sa_flags; - union { - __sanitizer_sigactionhandler_ptr sigaction; - __sanitizer_sighandler_ptr handler; - }; - __sanitizer_sigset_t sa_mask; - void (*sa_restorer)(); +struct __sanitizer_sigaction { + unsigned sa_flags; + union { + __sanitizer_sigactionhandler_ptr sigaction; + __sanitizer_sighandler_ptr handler; }; + __sanitizer_sigset_t sa_mask; + void (*sa_restorer)(); +}; #elif SANITIZER_ANDROID && SANITIZER_MIPS32 // check this before WORDSIZE == 32 - struct __sanitizer_sigaction { - unsigned sa_flags; - union { - __sanitizer_sigactionhandler_ptr sigaction; - __sanitizer_sighandler_ptr handler; - }; - __sanitizer_sigset_t sa_mask; +struct __sanitizer_sigaction { + unsigned sa_flags; + union { + __sanitizer_sigactionhandler_ptr sigaction; + __sanitizer_sighandler_ptr handler; }; + __sanitizer_sigset_t sa_mask; +}; #elif SANITIZER_ANDROID && (SANITIZER_WORDSIZE == 32) - struct __sanitizer_sigaction { - union { - __sanitizer_sigactionhandler_ptr sigaction; - __sanitizer_sighandler_ptr handler; - }; - __sanitizer_sigset_t sa_mask; - uptr sa_flags; - void (*sa_restorer)(); +struct __sanitizer_sigaction { + union { + __sanitizer_sigactionhandler_ptr sigaction; + __sanitizer_sighandler_ptr handler; }; + __sanitizer_sigset_t sa_mask; + uptr sa_flags; + void (*sa_restorer)(); +}; #else // !SANITIZER_ANDROID - struct __sanitizer_sigaction { +struct __sanitizer_sigaction { #if defined(__mips__) && !SANITIZER_FREEBSD - unsigned int sa_flags; + unsigned int sa_flags; #endif - union { - __sanitizer_sigactionhandler_ptr sigaction; - __sanitizer_sighandler_ptr handler; - }; + union { + __sanitizer_sigactionhandler_ptr sigaction; + __sanitizer_sighandler_ptr handler; + }; #if SANITIZER_FREEBSD - int sa_flags; - __sanitizer_sigset_t sa_mask; + int sa_flags; + __sanitizer_sigset_t sa_mask; #else #if defined(__s390x__) - int sa_resv; + int sa_resv; #else - __sanitizer_sigset_t sa_mask; + __sanitizer_sigset_t sa_mask; #endif #ifndef __mips__ #if defined(__sparc__) #if __GLIBC_PREREQ (2, 20) - // On sparc glibc 2.19 and earlier sa_flags was unsigned long. + // On sparc glibc 2.19 and earlier sa_flags was unsigned long. #if defined(__arch64__) - // To maintain ABI compatibility on sparc64 when switching to an int, - // __glibc_reserved0 was added. - int __glibc_reserved0; + // To maintain ABI compatibility on sparc64 when switching to an int, + // __glibc_reserved0 was added. + int __glibc_reserved0; #endif - int sa_flags; + int sa_flags; #else - unsigned long sa_flags; + unsigned long sa_flags; #endif #else - int sa_flags; + int sa_flags; #endif #endif #endif #if SANITIZER_LINUX - void (*sa_restorer)(); + void (*sa_restorer)(); #endif #if defined(__mips__) && (SANITIZER_WORDSIZE == 32) - int sa_resv[1]; + int sa_resv[1]; #endif #if defined(__s390x__) - __sanitizer_sigset_t sa_mask; + __sanitizer_sigset_t sa_mask; #endif - }; +}; #endif // !SANITIZER_ANDROID #if defined(__mips__) - struct __sanitizer_kernel_sigset_t { - uptr sig[2]; - }; +struct __sanitizer_kernel_sigset_t { + uptr sig[2]; +}; #else - struct __sanitizer_kernel_sigset_t { - u8 sig[8]; - }; +struct __sanitizer_kernel_sigset_t { + u8 sig[8]; +}; #endif - // Linux system headers define the 'sa_handler' and 'sa_sigaction' macros. +// Linux system headers define the 'sa_handler' and 'sa_sigaction' macros. #if SANITIZER_MIPS - struct __sanitizer_kernel_sigaction_t { - unsigned int sa_flags; - union { - void (*handler)(int signo); - void (*sigaction)(int signo, __sanitizer_siginfo *info, void *ctx); - }; - __sanitizer_kernel_sigset_t sa_mask; - void (*sa_restorer)(void); +struct __sanitizer_kernel_sigaction_t { + unsigned int sa_flags; + union { + void (*handler)(int signo); + void (*sigaction)(int signo, __sanitizer_siginfo *info, void *ctx); }; + __sanitizer_kernel_sigset_t sa_mask; + void (*sa_restorer)(void); +}; #else - struct __sanitizer_kernel_sigaction_t { - union { - void (*handler)(int signo); - void (*sigaction)(int signo, __sanitizer_siginfo *info, void *ctx); - }; - unsigned long sa_flags; - void (*sa_restorer)(void); - __sanitizer_kernel_sigset_t sa_mask; +struct __sanitizer_kernel_sigaction_t { + union { + void (*handler)(int signo); + void (*sigaction)(int signo, __sanitizer_siginfo *info, void *ctx); }; + unsigned long sa_flags; + void (*sa_restorer)(void); + __sanitizer_kernel_sigset_t sa_mask; +}; #endif - extern const uptr sig_ign; - extern const uptr sig_dfl; - extern const uptr sig_err; - extern const uptr sa_siginfo; +extern const uptr sig_ign; +extern const uptr sig_dfl; +extern const uptr sig_err; +extern const uptr sa_siginfo; #if SANITIZER_LINUX - extern int e_tabsz; +extern int e_tabsz; #endif - extern int af_inet; - extern int af_inet6; - uptr __sanitizer_in_addr_sz(int af); +extern int af_inet; +extern int af_inet6; +uptr __sanitizer_in_addr_sz(int af); #if SANITIZER_LINUX - struct __sanitizer_dl_phdr_info { - uptr dlpi_addr; - const char *dlpi_name; - const void *dlpi_phdr; - short dlpi_phnum; - }; +struct __sanitizer_dl_phdr_info { + uptr dlpi_addr; + const char *dlpi_name; + const void *dlpi_phdr; + short dlpi_phnum; +}; - extern unsigned struct_ElfW_Phdr_sz; +extern unsigned struct_ElfW_Phdr_sz; #endif - struct __sanitizer_addrinfo { - int ai_flags; - int ai_family; - int ai_socktype; - int ai_protocol; +struct __sanitizer_addrinfo { + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; #if SANITIZER_ANDROID || SANITIZER_MAC - unsigned ai_addrlen; - char *ai_canonname; - void *ai_addr; + unsigned ai_addrlen; + char *ai_canonname; + void *ai_addr; #else // LINUX - unsigned ai_addrlen; - void *ai_addr; - char *ai_canonname; + unsigned ai_addrlen; + void *ai_addr; + char *ai_canonname; #endif - struct __sanitizer_addrinfo *ai_next; - }; + struct __sanitizer_addrinfo *ai_next; +}; - struct __sanitizer_hostent { - char *h_name; - char **h_aliases; - int h_addrtype; - int h_length; - char **h_addr_list; - }; +struct __sanitizer_hostent { + char *h_name; + char **h_aliases; + int h_addrtype; + int h_length; + char **h_addr_list; +}; - struct __sanitizer_pollfd { - int fd; - short events; - short revents; - }; +struct __sanitizer_pollfd { + int fd; + short events; + short revents; +}; #if SANITIZER_ANDROID || SANITIZER_MAC - typedef unsigned __sanitizer_nfds_t; +typedef unsigned __sanitizer_nfds_t; #else - typedef unsigned long __sanitizer_nfds_t; +typedef unsigned long __sanitizer_nfds_t; #endif #if !SANITIZER_ANDROID # if SANITIZER_LINUX - struct __sanitizer_glob_t { - uptr gl_pathc; - char **gl_pathv; - uptr gl_offs; - int gl_flags; - - void (*gl_closedir)(void *dirp); - void *(*gl_readdir)(void *dirp); - void *(*gl_opendir)(const char *); - int (*gl_lstat)(const char *, void *); - int (*gl_stat)(const char *, void *); - }; +struct __sanitizer_glob_t { + uptr gl_pathc; + char **gl_pathv; + uptr gl_offs; + int gl_flags; + + void (*gl_closedir)(void *dirp); + void *(*gl_readdir)(void *dirp); + void *(*gl_opendir)(const char *); + int (*gl_lstat)(const char *, void *); + int (*gl_stat)(const char *, void *); +}; # endif // SANITIZER_LINUX # if SANITIZER_LINUX - extern int glob_nomatch; - extern int glob_altdirfunc; +extern int glob_nomatch; +extern int glob_altdirfunc; # endif #endif // !SANITIZER_ANDROID - extern unsigned path_max; +extern unsigned path_max; - struct __sanitizer_wordexp_t { - uptr we_wordc; - char **we_wordv; - uptr we_offs; - }; +struct __sanitizer_wordexp_t { + uptr we_wordc; + char **we_wordv; + uptr we_offs; +}; #if SANITIZER_LINUX && !SANITIZER_ANDROID - struct __sanitizer_FILE { - int _flags; - char *_IO_read_ptr; - char *_IO_read_end; - char *_IO_read_base; - char *_IO_write_base; - char *_IO_write_ptr; - char *_IO_write_end; - char *_IO_buf_base; - char *_IO_buf_end; - char *_IO_save_base; - char *_IO_backup_base; - char *_IO_save_end; - void *_markers; - __sanitizer_FILE *_chain; - int _fileno; - }; +struct __sanitizer_FILE { + int _flags; + char *_IO_read_ptr; + char *_IO_read_end; + char *_IO_read_base; + char *_IO_write_base; + char *_IO_write_ptr; + char *_IO_write_end; + char *_IO_buf_base; + char *_IO_buf_end; + char *_IO_save_base; + char *_IO_backup_base; + char *_IO_save_end; + void *_markers; + __sanitizer_FILE *_chain; + int _fileno; +}; # define SANITIZER_HAS_STRUCT_FILE 1 #else - typedef void __sanitizer_FILE; +typedef void __sanitizer_FILE; # define SANITIZER_HAS_STRUCT_FILE 0 #endif -#if SANITIZER_LINUX && !SANITIZER_ANDROID && \ - (defined(__i386) || defined(__x86_64) || defined(__mips64) || \ - defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__) || \ - defined(__s390__)) - extern unsigned struct_user_regs_struct_sz; - extern unsigned struct_user_fpregs_struct_sz; - extern unsigned struct_user_fpxregs_struct_sz; - extern unsigned struct_user_vfpregs_struct_sz; - - extern int ptrace_peektext; - extern int ptrace_peekdata; - extern int ptrace_peekuser; - extern int ptrace_getregs; - extern int ptrace_setregs; - extern int ptrace_getfpregs; - extern int ptrace_setfpregs; - extern int ptrace_getfpxregs; - extern int ptrace_setfpxregs; - extern int ptrace_getvfpregs; - extern int ptrace_setvfpregs; - extern int ptrace_getsiginfo; - extern int ptrace_setsiginfo; - extern int ptrace_getregset; - extern int ptrace_setregset; - extern int ptrace_geteventmsg; +#if SANITIZER_LINUX && !SANITIZER_ANDROID && \ + (defined(__i386) || defined(__x86_64) || defined(__mips64) || \ + defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__) || \ + defined(__s390__)) +extern unsigned struct_user_regs_struct_sz; +extern unsigned struct_user_fpregs_struct_sz; +extern unsigned struct_user_fpxregs_struct_sz; +extern unsigned struct_user_vfpregs_struct_sz; + +extern int ptrace_peektext; +extern int ptrace_peekdata; +extern int ptrace_peekuser; +extern int ptrace_getregs; +extern int ptrace_setregs; +extern int ptrace_getfpregs; +extern int ptrace_setfpregs; +extern int ptrace_getfpxregs; +extern int ptrace_setfpxregs; +extern int ptrace_getvfpregs; +extern int ptrace_setvfpregs; +extern int ptrace_getsiginfo; +extern int ptrace_setsiginfo; +extern int ptrace_getregset; +extern int ptrace_setregset; +extern int ptrace_geteventmsg; #endif #if SANITIZER_LINUX && !SANITIZER_ANDROID - 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; +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; #endif #if !SANITIZER_MAC && !SANITIZER_FREEBSD - extern unsigned struct_utmp_sz; +extern unsigned struct_utmp_sz; #endif #if !SANITIZER_ANDROID - extern unsigned struct_utmpx_sz; +extern unsigned struct_utmpx_sz; #endif - extern int map_fixed; +extern int map_fixed; - // ioctl arguments - struct __sanitizer_ifconf { - int ifc_len; - union { - void *ifcu_req; - } ifc_ifcu; +// ioctl arguments +struct __sanitizer_ifconf { + int ifc_len; + union { + void *ifcu_req; + } ifc_ifcu; #if SANITIZER_MAC - } __attribute__((packed)); +} __attribute__((packed)); #else - }; +}; #endif #if SANITIZER_LINUX && !SANITIZER_ANDROID @@ -932,519 +934,519 @@ struct __sanitizer_cookie_io_functions_t { #define IOC_SIZE(nr) (((nr) >> IOC_SIZESHIFT) & IOC_SIZEMASK) #endif - extern unsigned struct_ifreq_sz; - extern unsigned struct_termios_sz; - extern unsigned struct_winsize_sz; +extern unsigned struct_ifreq_sz; +extern unsigned struct_termios_sz; +extern unsigned struct_winsize_sz; #if SANITIZER_LINUX - extern unsigned struct_arpreq_sz; - extern unsigned struct_cdrom_msf_sz; - extern unsigned struct_cdrom_multisession_sz; - extern unsigned struct_cdrom_read_audio_sz; - extern unsigned struct_cdrom_subchnl_sz; - extern unsigned struct_cdrom_ti_sz; - extern unsigned struct_cdrom_tocentry_sz; - extern unsigned struct_cdrom_tochdr_sz; - extern unsigned struct_cdrom_volctrl_sz; - extern unsigned struct_ff_effect_sz; - extern unsigned struct_floppy_drive_params_sz; - extern unsigned struct_floppy_drive_struct_sz; - extern unsigned struct_floppy_fdc_state_sz; - extern unsigned struct_floppy_max_errors_sz; - extern unsigned struct_floppy_raw_cmd_sz; - extern unsigned struct_floppy_struct_sz; - extern unsigned struct_floppy_write_errors_sz; - extern unsigned struct_format_descr_sz; - extern unsigned struct_hd_driveid_sz; - extern unsigned struct_hd_geometry_sz; - extern unsigned struct_input_absinfo_sz; - extern unsigned struct_input_id_sz; - extern unsigned struct_mtpos_sz; - extern unsigned struct_termio_sz; - extern unsigned struct_vt_consize_sz; - extern unsigned struct_vt_sizes_sz; - extern unsigned struct_vt_stat_sz; +extern unsigned struct_arpreq_sz; +extern unsigned struct_cdrom_msf_sz; +extern unsigned struct_cdrom_multisession_sz; +extern unsigned struct_cdrom_read_audio_sz; +extern unsigned struct_cdrom_subchnl_sz; +extern unsigned struct_cdrom_ti_sz; +extern unsigned struct_cdrom_tocentry_sz; +extern unsigned struct_cdrom_tochdr_sz; +extern unsigned struct_cdrom_volctrl_sz; +extern unsigned struct_ff_effect_sz; +extern unsigned struct_floppy_drive_params_sz; +extern unsigned struct_floppy_drive_struct_sz; +extern unsigned struct_floppy_fdc_state_sz; +extern unsigned struct_floppy_max_errors_sz; +extern unsigned struct_floppy_raw_cmd_sz; +extern unsigned struct_floppy_struct_sz; +extern unsigned struct_floppy_write_errors_sz; +extern unsigned struct_format_descr_sz; +extern unsigned struct_hd_driveid_sz; +extern unsigned struct_hd_geometry_sz; +extern unsigned struct_input_absinfo_sz; +extern unsigned struct_input_id_sz; +extern unsigned struct_mtpos_sz; +extern unsigned struct_termio_sz; +extern unsigned struct_vt_consize_sz; +extern unsigned struct_vt_sizes_sz; +extern unsigned struct_vt_stat_sz; #endif // SANITIZER_LINUX #if SANITIZER_LINUX - extern unsigned struct_copr_buffer_sz; - extern unsigned struct_copr_debug_buf_sz; - extern unsigned struct_copr_msg_sz; - extern unsigned struct_midi_info_sz; - extern unsigned struct_mtget_sz; - extern unsigned struct_mtop_sz; - extern unsigned struct_rtentry_sz; - extern unsigned struct_sbi_instrument_sz; - extern unsigned struct_seq_event_rec_sz; - extern unsigned struct_synth_info_sz; - extern unsigned struct_vt_mode_sz; +extern unsigned struct_copr_buffer_sz; +extern unsigned struct_copr_debug_buf_sz; +extern unsigned struct_copr_msg_sz; +extern unsigned struct_midi_info_sz; +extern unsigned struct_mtget_sz; +extern unsigned struct_mtop_sz; +extern unsigned struct_rtentry_sz; +extern unsigned struct_sbi_instrument_sz; +extern unsigned struct_seq_event_rec_sz; +extern unsigned struct_synth_info_sz; +extern unsigned struct_vt_mode_sz; #endif // SANITIZER_LINUX #if SANITIZER_LINUX && !SANITIZER_ANDROID - extern unsigned struct_ax25_parms_struct_sz; - extern unsigned struct_cyclades_monitor_sz; - extern unsigned struct_input_keymap_entry_sz; - extern unsigned struct_ipx_config_data_sz; - extern unsigned struct_kbdiacrs_sz; - extern unsigned struct_kbentry_sz; - extern unsigned struct_kbkeycode_sz; - extern unsigned struct_kbsentry_sz; - extern unsigned struct_mtconfiginfo_sz; - extern unsigned struct_nr_parms_struct_sz; - extern unsigned struct_scc_modem_sz; - extern unsigned struct_scc_stat_sz; - extern unsigned struct_serial_multiport_struct_sz; - extern unsigned struct_serial_struct_sz; - extern unsigned struct_sockaddr_ax25_sz; - extern unsigned struct_unimapdesc_sz; - extern unsigned struct_unimapinit_sz; +extern unsigned struct_ax25_parms_struct_sz; +extern unsigned struct_cyclades_monitor_sz; +extern unsigned struct_input_keymap_entry_sz; +extern unsigned struct_ipx_config_data_sz; +extern unsigned struct_kbdiacrs_sz; +extern unsigned struct_kbentry_sz; +extern unsigned struct_kbkeycode_sz; +extern unsigned struct_kbsentry_sz; +extern unsigned struct_mtconfiginfo_sz; +extern unsigned struct_nr_parms_struct_sz; +extern unsigned struct_scc_modem_sz; +extern unsigned struct_scc_stat_sz; +extern unsigned struct_serial_multiport_struct_sz; +extern unsigned struct_serial_struct_sz; +extern unsigned struct_sockaddr_ax25_sz; +extern unsigned struct_unimapdesc_sz; +extern unsigned struct_unimapinit_sz; #endif // SANITIZER_LINUX && !SANITIZER_ANDROID - extern const unsigned long __sanitizer_bufsiz; +extern const unsigned long __sanitizer_bufsiz; #if SANITIZER_LINUX && !SANITIZER_ANDROID - extern unsigned struct_audio_buf_info_sz; - extern unsigned struct_ppp_stats_sz; +extern unsigned struct_audio_buf_info_sz; +extern unsigned struct_ppp_stats_sz; #endif // (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID #if !SANITIZER_ANDROID && !SANITIZER_MAC - extern unsigned struct_sioc_sg_req_sz; - extern unsigned struct_sioc_vif_req_sz; -#endif - - // ioctl request identifiers - - // A special value to mark ioctls that are not present on the target platform, - // when it can not be determined without including any system headers. - extern const unsigned IOCTL_NOT_PRESENT; - - extern unsigned IOCTL_FIOASYNC; - extern unsigned IOCTL_FIOCLEX; - extern unsigned IOCTL_FIOGETOWN; - extern unsigned IOCTL_FIONBIO; - extern unsigned IOCTL_FIONCLEX; - extern unsigned IOCTL_FIOSETOWN; - extern unsigned IOCTL_SIOCADDMULTI; - extern unsigned IOCTL_SIOCATMARK; - extern unsigned IOCTL_SIOCDELMULTI; - extern unsigned IOCTL_SIOCGIFADDR; - extern unsigned IOCTL_SIOCGIFBRDADDR; - extern unsigned IOCTL_SIOCGIFCONF; - extern unsigned IOCTL_SIOCGIFDSTADDR; - extern unsigned IOCTL_SIOCGIFFLAGS; - extern unsigned IOCTL_SIOCGIFMETRIC; - extern unsigned IOCTL_SIOCGIFMTU; - extern unsigned IOCTL_SIOCGIFNETMASK; - extern unsigned IOCTL_SIOCGPGRP; - extern unsigned IOCTL_SIOCSIFADDR; - extern unsigned IOCTL_SIOCSIFBRDADDR; - extern unsigned IOCTL_SIOCSIFDSTADDR; - extern unsigned IOCTL_SIOCSIFFLAGS; - extern unsigned IOCTL_SIOCSIFMETRIC; - extern unsigned IOCTL_SIOCSIFMTU; - extern unsigned IOCTL_SIOCSIFNETMASK; - extern unsigned IOCTL_SIOCSPGRP; - extern unsigned IOCTL_TIOCCONS; - extern unsigned IOCTL_TIOCEXCL; - extern unsigned IOCTL_TIOCGETD; - extern unsigned IOCTL_TIOCGPGRP; - extern unsigned IOCTL_TIOCGWINSZ; - extern unsigned IOCTL_TIOCMBIC; - extern unsigned IOCTL_TIOCMBIS; - extern unsigned IOCTL_TIOCMGET; - extern unsigned IOCTL_TIOCMSET; - extern unsigned IOCTL_TIOCNOTTY; - extern unsigned IOCTL_TIOCNXCL; - extern unsigned IOCTL_TIOCOUTQ; - extern unsigned IOCTL_TIOCPKT; - extern unsigned IOCTL_TIOCSCTTY; - extern unsigned IOCTL_TIOCSETD; - extern unsigned IOCTL_TIOCSPGRP; - extern unsigned IOCTL_TIOCSTI; - extern unsigned IOCTL_TIOCSWINSZ; +extern unsigned struct_sioc_sg_req_sz; +extern unsigned struct_sioc_vif_req_sz; +#endif + +// ioctl request identifiers + +// A special value to mark ioctls that are not present on the target platform, +// when it can not be determined without including any system headers. +extern const unsigned IOCTL_NOT_PRESENT; + +extern unsigned IOCTL_FIOASYNC; +extern unsigned IOCTL_FIOCLEX; +extern unsigned IOCTL_FIOGETOWN; +extern unsigned IOCTL_FIONBIO; +extern unsigned IOCTL_FIONCLEX; +extern unsigned IOCTL_FIOSETOWN; +extern unsigned IOCTL_SIOCADDMULTI; +extern unsigned IOCTL_SIOCATMARK; +extern unsigned IOCTL_SIOCDELMULTI; +extern unsigned IOCTL_SIOCGIFADDR; +extern unsigned IOCTL_SIOCGIFBRDADDR; +extern unsigned IOCTL_SIOCGIFCONF; +extern unsigned IOCTL_SIOCGIFDSTADDR; +extern unsigned IOCTL_SIOCGIFFLAGS; +extern unsigned IOCTL_SIOCGIFMETRIC; +extern unsigned IOCTL_SIOCGIFMTU; +extern unsigned IOCTL_SIOCGIFNETMASK; +extern unsigned IOCTL_SIOCGPGRP; +extern unsigned IOCTL_SIOCSIFADDR; +extern unsigned IOCTL_SIOCSIFBRDADDR; +extern unsigned IOCTL_SIOCSIFDSTADDR; +extern unsigned IOCTL_SIOCSIFFLAGS; +extern unsigned IOCTL_SIOCSIFMETRIC; +extern unsigned IOCTL_SIOCSIFMTU; +extern unsigned IOCTL_SIOCSIFNETMASK; +extern unsigned IOCTL_SIOCSPGRP; +extern unsigned IOCTL_TIOCCONS; +extern unsigned IOCTL_TIOCEXCL; +extern unsigned IOCTL_TIOCGETD; +extern unsigned IOCTL_TIOCGPGRP; +extern unsigned IOCTL_TIOCGWINSZ; +extern unsigned IOCTL_TIOCMBIC; +extern unsigned IOCTL_TIOCMBIS; +extern unsigned IOCTL_TIOCMGET; +extern unsigned IOCTL_TIOCMSET; +extern unsigned IOCTL_TIOCNOTTY; +extern unsigned IOCTL_TIOCNXCL; +extern unsigned IOCTL_TIOCOUTQ; +extern unsigned IOCTL_TIOCPKT; +extern unsigned IOCTL_TIOCSCTTY; +extern unsigned IOCTL_TIOCSETD; +extern unsigned IOCTL_TIOCSPGRP; +extern unsigned IOCTL_TIOCSTI; +extern unsigned IOCTL_TIOCSWINSZ; #if SANITIZER_LINUX && !SANITIZER_ANDROID - extern unsigned IOCTL_SIOCGETSGCNT; - extern unsigned IOCTL_SIOCGETVIFCNT; +extern unsigned IOCTL_SIOCGETSGCNT; +extern unsigned IOCTL_SIOCGETVIFCNT; #endif #if SANITIZER_LINUX - extern unsigned IOCTL_EVIOCGABS; - extern unsigned IOCTL_EVIOCGBIT; - extern unsigned IOCTL_EVIOCGEFFECTS; - extern unsigned IOCTL_EVIOCGID; - extern unsigned IOCTL_EVIOCGKEY; - extern unsigned IOCTL_EVIOCGKEYCODE; - extern unsigned IOCTL_EVIOCGLED; - extern unsigned IOCTL_EVIOCGNAME; - extern unsigned IOCTL_EVIOCGPHYS; - extern unsigned IOCTL_EVIOCGRAB; - extern unsigned IOCTL_EVIOCGREP; - extern unsigned IOCTL_EVIOCGSND; - extern unsigned IOCTL_EVIOCGSW; - extern unsigned IOCTL_EVIOCGUNIQ; - extern unsigned IOCTL_EVIOCGVERSION; - extern unsigned IOCTL_EVIOCRMFF; - extern unsigned IOCTL_EVIOCSABS; - extern unsigned IOCTL_EVIOCSFF; - extern unsigned IOCTL_EVIOCSKEYCODE; - extern unsigned IOCTL_EVIOCSREP; - extern unsigned IOCTL_BLKFLSBUF; - extern unsigned IOCTL_BLKGETSIZE; - extern unsigned IOCTL_BLKRAGET; - extern unsigned IOCTL_BLKRASET; - extern unsigned IOCTL_BLKROGET; - extern unsigned IOCTL_BLKROSET; - extern unsigned IOCTL_BLKRRPART; - extern unsigned IOCTL_CDROMAUDIOBUFSIZ; - extern unsigned IOCTL_CDROMEJECT; - extern unsigned IOCTL_CDROMEJECT_SW; - extern unsigned IOCTL_CDROMMULTISESSION; - extern unsigned IOCTL_CDROMPAUSE; - extern unsigned IOCTL_CDROMPLAYMSF; - extern unsigned IOCTL_CDROMPLAYTRKIND; - extern unsigned IOCTL_CDROMREADAUDIO; - extern unsigned IOCTL_CDROMREADCOOKED; - extern unsigned IOCTL_CDROMREADMODE1; - extern unsigned IOCTL_CDROMREADMODE2; - extern unsigned IOCTL_CDROMREADRAW; - extern unsigned IOCTL_CDROMREADTOCENTRY; - extern unsigned IOCTL_CDROMREADTOCHDR; - extern unsigned IOCTL_CDROMRESET; - extern unsigned IOCTL_CDROMRESUME; - extern unsigned IOCTL_CDROMSEEK; - extern unsigned IOCTL_CDROMSTART; - extern unsigned IOCTL_CDROMSTOP; - extern unsigned IOCTL_CDROMSUBCHNL; - extern unsigned IOCTL_CDROMVOLCTRL; - extern unsigned IOCTL_CDROMVOLREAD; - extern unsigned IOCTL_CDROM_GET_UPC; - extern unsigned IOCTL_FDCLRPRM; - extern unsigned IOCTL_FDDEFPRM; - extern unsigned IOCTL_FDFLUSH; - extern unsigned IOCTL_FDFMTBEG; - extern unsigned IOCTL_FDFMTEND; - extern unsigned IOCTL_FDFMTTRK; - extern unsigned IOCTL_FDGETDRVPRM; - extern unsigned IOCTL_FDGETDRVSTAT; - extern unsigned IOCTL_FDGETDRVTYP; - extern unsigned IOCTL_FDGETFDCSTAT; - extern unsigned IOCTL_FDGETMAXERRS; - extern unsigned IOCTL_FDGETPRM; - extern unsigned IOCTL_FDMSGOFF; - extern unsigned IOCTL_FDMSGON; - extern unsigned IOCTL_FDPOLLDRVSTAT; - extern unsigned IOCTL_FDRAWCMD; - extern unsigned IOCTL_FDRESET; - extern unsigned IOCTL_FDSETDRVPRM; - extern unsigned IOCTL_FDSETEMSGTRESH; - extern unsigned IOCTL_FDSETMAXERRS; - extern unsigned IOCTL_FDSETPRM; - extern unsigned IOCTL_FDTWADDLE; - extern unsigned IOCTL_FDWERRORCLR; - extern unsigned IOCTL_FDWERRORGET; - extern unsigned IOCTL_HDIO_DRIVE_CMD; - extern unsigned IOCTL_HDIO_GETGEO; - extern unsigned IOCTL_HDIO_GET_32BIT; - extern unsigned IOCTL_HDIO_GET_DMA; - extern unsigned IOCTL_HDIO_GET_IDENTITY; - extern unsigned IOCTL_HDIO_GET_KEEPSETTINGS; - extern unsigned IOCTL_HDIO_GET_MULTCOUNT; - extern unsigned IOCTL_HDIO_GET_NOWERR; - extern unsigned IOCTL_HDIO_GET_UNMASKINTR; - extern unsigned IOCTL_HDIO_SET_32BIT; - extern unsigned IOCTL_HDIO_SET_DMA; - extern unsigned IOCTL_HDIO_SET_KEEPSETTINGS; - extern unsigned IOCTL_HDIO_SET_MULTCOUNT; - extern unsigned IOCTL_HDIO_SET_NOWERR; - extern unsigned IOCTL_HDIO_SET_UNMASKINTR; - extern unsigned IOCTL_MTIOCPOS; - extern unsigned IOCTL_PPPIOCGASYNCMAP; - extern unsigned IOCTL_PPPIOCGDEBUG; - extern unsigned IOCTL_PPPIOCGFLAGS; - extern unsigned IOCTL_PPPIOCGUNIT; - extern unsigned IOCTL_PPPIOCGXASYNCMAP; - extern unsigned IOCTL_PPPIOCSASYNCMAP; - extern unsigned IOCTL_PPPIOCSDEBUG; - extern unsigned IOCTL_PPPIOCSFLAGS; - extern unsigned IOCTL_PPPIOCSMAXCID; - extern unsigned IOCTL_PPPIOCSMRU; - extern unsigned IOCTL_PPPIOCSXASYNCMAP; - extern unsigned IOCTL_SIOCDARP; - extern unsigned IOCTL_SIOCDRARP; - extern unsigned IOCTL_SIOCGARP; - extern unsigned IOCTL_SIOCGIFENCAP; - extern unsigned IOCTL_SIOCGIFHWADDR; - extern unsigned IOCTL_SIOCGIFMAP; - extern unsigned IOCTL_SIOCGIFMEM; - extern unsigned IOCTL_SIOCGIFNAME; - extern unsigned IOCTL_SIOCGIFSLAVE; - extern unsigned IOCTL_SIOCGRARP; - extern unsigned IOCTL_SIOCGSTAMP; - extern unsigned IOCTL_SIOCSARP; - extern unsigned IOCTL_SIOCSIFENCAP; - extern unsigned IOCTL_SIOCSIFHWADDR; - extern unsigned IOCTL_SIOCSIFLINK; - extern unsigned IOCTL_SIOCSIFMAP; - extern unsigned IOCTL_SIOCSIFMEM; - extern unsigned IOCTL_SIOCSIFSLAVE; - extern unsigned IOCTL_SIOCSRARP; - extern unsigned IOCTL_SNDCTL_COPR_HALT; - extern unsigned IOCTL_SNDCTL_COPR_LOAD; - extern unsigned IOCTL_SNDCTL_COPR_RCODE; - extern unsigned IOCTL_SNDCTL_COPR_RCVMSG; - extern unsigned IOCTL_SNDCTL_COPR_RDATA; - extern unsigned IOCTL_SNDCTL_COPR_RESET; - extern unsigned IOCTL_SNDCTL_COPR_RUN; - extern unsigned IOCTL_SNDCTL_COPR_SENDMSG; - extern unsigned IOCTL_SNDCTL_COPR_WCODE; - extern unsigned IOCTL_SNDCTL_COPR_WDATA; - extern unsigned IOCTL_TCFLSH; - extern unsigned IOCTL_TCGETA; - extern unsigned IOCTL_TCGETS; - extern unsigned IOCTL_TCSBRK; - extern unsigned IOCTL_TCSBRKP; - extern unsigned IOCTL_TCSETA; - extern unsigned IOCTL_TCSETAF; - extern unsigned IOCTL_TCSETAW; - extern unsigned IOCTL_TCSETS; - extern unsigned IOCTL_TCSETSF; - extern unsigned IOCTL_TCSETSW; - extern unsigned IOCTL_TCXONC; - extern unsigned IOCTL_TIOCGLCKTRMIOS; - extern unsigned IOCTL_TIOCGSOFTCAR; - extern unsigned IOCTL_TIOCINQ; - extern unsigned IOCTL_TIOCLINUX; - extern unsigned IOCTL_TIOCSERCONFIG; - extern unsigned IOCTL_TIOCSERGETLSR; - extern unsigned IOCTL_TIOCSERGWILD; - extern unsigned IOCTL_TIOCSERSWILD; - extern unsigned IOCTL_TIOCSLCKTRMIOS; - extern unsigned IOCTL_TIOCSSOFTCAR; - extern unsigned IOCTL_VT_DISALLOCATE; - extern unsigned IOCTL_VT_GETSTATE; - extern unsigned IOCTL_VT_RESIZE; - extern unsigned IOCTL_VT_RESIZEX; - extern unsigned IOCTL_VT_SENDSIG; - extern unsigned IOCTL_MTIOCGET; - extern unsigned IOCTL_MTIOCTOP; - extern unsigned IOCTL_SIOCADDRT; - extern unsigned IOCTL_SIOCDELRT; - extern unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE; - extern unsigned IOCTL_SNDCTL_DSP_GETFMTS; - extern unsigned IOCTL_SNDCTL_DSP_NONBLOCK; - extern unsigned IOCTL_SNDCTL_DSP_POST; - extern unsigned IOCTL_SNDCTL_DSP_RESET; - extern unsigned IOCTL_SNDCTL_DSP_SETFMT; - extern unsigned IOCTL_SNDCTL_DSP_SETFRAGMENT; - extern unsigned IOCTL_SNDCTL_DSP_SPEED; - extern unsigned IOCTL_SNDCTL_DSP_STEREO; - extern unsigned IOCTL_SNDCTL_DSP_SUBDIVIDE; - extern unsigned IOCTL_SNDCTL_DSP_SYNC; - extern unsigned IOCTL_SNDCTL_FM_4OP_ENABLE; - extern unsigned IOCTL_SNDCTL_FM_LOAD_INSTR; - extern unsigned IOCTL_SNDCTL_MIDI_INFO; - extern unsigned IOCTL_SNDCTL_MIDI_PRETIME; - extern unsigned IOCTL_SNDCTL_SEQ_CTRLRATE; - extern unsigned IOCTL_SNDCTL_SEQ_GETINCOUNT; - extern unsigned IOCTL_SNDCTL_SEQ_GETOUTCOUNT; - extern unsigned IOCTL_SNDCTL_SEQ_NRMIDIS; - extern unsigned IOCTL_SNDCTL_SEQ_NRSYNTHS; - extern unsigned IOCTL_SNDCTL_SEQ_OUTOFBAND; - extern unsigned IOCTL_SNDCTL_SEQ_PANIC; - extern unsigned IOCTL_SNDCTL_SEQ_PERCMODE; - extern unsigned IOCTL_SNDCTL_SEQ_RESET; - extern unsigned IOCTL_SNDCTL_SEQ_RESETSAMPLES; - extern unsigned IOCTL_SNDCTL_SEQ_SYNC; - extern unsigned IOCTL_SNDCTL_SEQ_TESTMIDI; - extern unsigned IOCTL_SNDCTL_SEQ_THRESHOLD; - extern unsigned IOCTL_SNDCTL_SYNTH_INFO; - extern unsigned IOCTL_SNDCTL_SYNTH_MEMAVL; - extern unsigned IOCTL_SNDCTL_TMR_CONTINUE; - extern unsigned IOCTL_SNDCTL_TMR_METRONOME; - extern unsigned IOCTL_SNDCTL_TMR_SELECT; - extern unsigned IOCTL_SNDCTL_TMR_SOURCE; - extern unsigned IOCTL_SNDCTL_TMR_START; - extern unsigned IOCTL_SNDCTL_TMR_STOP; - extern unsigned IOCTL_SNDCTL_TMR_TEMPO; - extern unsigned IOCTL_SNDCTL_TMR_TIMEBASE; - extern unsigned IOCTL_SOUND_MIXER_READ_ALTPCM; - extern unsigned IOCTL_SOUND_MIXER_READ_BASS; - extern unsigned IOCTL_SOUND_MIXER_READ_CAPS; - extern unsigned IOCTL_SOUND_MIXER_READ_CD; - extern unsigned IOCTL_SOUND_MIXER_READ_DEVMASK; - extern unsigned IOCTL_SOUND_MIXER_READ_ENHANCE; - extern unsigned IOCTL_SOUND_MIXER_READ_IGAIN; - extern unsigned IOCTL_SOUND_MIXER_READ_IMIX; - extern unsigned IOCTL_SOUND_MIXER_READ_LINE1; - extern unsigned IOCTL_SOUND_MIXER_READ_LINE2; - extern unsigned IOCTL_SOUND_MIXER_READ_LINE3; - extern unsigned IOCTL_SOUND_MIXER_READ_LINE; - extern unsigned IOCTL_SOUND_MIXER_READ_LOUD; - extern unsigned IOCTL_SOUND_MIXER_READ_MIC; - extern unsigned IOCTL_SOUND_MIXER_READ_MUTE; - extern unsigned IOCTL_SOUND_MIXER_READ_OGAIN; - extern unsigned IOCTL_SOUND_MIXER_READ_PCM; - extern unsigned IOCTL_SOUND_MIXER_READ_RECLEV; - extern unsigned IOCTL_SOUND_MIXER_READ_RECMASK; - extern unsigned IOCTL_SOUND_MIXER_READ_RECSRC; - extern unsigned IOCTL_SOUND_MIXER_READ_SPEAKER; - extern unsigned IOCTL_SOUND_MIXER_READ_STEREODEVS; - extern unsigned IOCTL_SOUND_MIXER_READ_SYNTH; - extern unsigned IOCTL_SOUND_MIXER_READ_TREBLE; - extern unsigned IOCTL_SOUND_MIXER_READ_VOLUME; - extern unsigned IOCTL_SOUND_MIXER_WRITE_ALTPCM; - extern unsigned IOCTL_SOUND_MIXER_WRITE_BASS; - extern unsigned IOCTL_SOUND_MIXER_WRITE_CD; - extern unsigned IOCTL_SOUND_MIXER_WRITE_ENHANCE; - extern unsigned IOCTL_SOUND_MIXER_WRITE_IGAIN; - extern unsigned IOCTL_SOUND_MIXER_WRITE_IMIX; - extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE1; - extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE2; - extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE3; - extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE; - extern unsigned IOCTL_SOUND_MIXER_WRITE_LOUD; - extern unsigned IOCTL_SOUND_MIXER_WRITE_MIC; - extern unsigned IOCTL_SOUND_MIXER_WRITE_MUTE; - extern unsigned IOCTL_SOUND_MIXER_WRITE_OGAIN; - extern unsigned IOCTL_SOUND_MIXER_WRITE_PCM; - extern unsigned IOCTL_SOUND_MIXER_WRITE_RECLEV; - extern unsigned IOCTL_SOUND_MIXER_WRITE_RECSRC; - extern unsigned IOCTL_SOUND_MIXER_WRITE_SPEAKER; - extern unsigned IOCTL_SOUND_MIXER_WRITE_SYNTH; - extern unsigned IOCTL_SOUND_MIXER_WRITE_TREBLE; - extern unsigned IOCTL_SOUND_MIXER_WRITE_VOLUME; - extern unsigned IOCTL_SOUND_PCM_READ_BITS; - extern unsigned IOCTL_SOUND_PCM_READ_CHANNELS; - extern unsigned IOCTL_SOUND_PCM_READ_FILTER; - extern unsigned IOCTL_SOUND_PCM_READ_RATE; - extern unsigned IOCTL_SOUND_PCM_WRITE_CHANNELS; - extern unsigned IOCTL_SOUND_PCM_WRITE_FILTER; - extern unsigned IOCTL_VT_ACTIVATE; - extern unsigned IOCTL_VT_GETMODE; - extern unsigned IOCTL_VT_OPENQRY; - extern unsigned IOCTL_VT_RELDISP; - extern unsigned IOCTL_VT_SETMODE; - extern unsigned IOCTL_VT_WAITACTIVE; +extern unsigned IOCTL_EVIOCGABS; +extern unsigned IOCTL_EVIOCGBIT; +extern unsigned IOCTL_EVIOCGEFFECTS; +extern unsigned IOCTL_EVIOCGID; +extern unsigned IOCTL_EVIOCGKEY; +extern unsigned IOCTL_EVIOCGKEYCODE; +extern unsigned IOCTL_EVIOCGLED; +extern unsigned IOCTL_EVIOCGNAME; +extern unsigned IOCTL_EVIOCGPHYS; +extern unsigned IOCTL_EVIOCGRAB; +extern unsigned IOCTL_EVIOCGREP; +extern unsigned IOCTL_EVIOCGSND; +extern unsigned IOCTL_EVIOCGSW; +extern unsigned IOCTL_EVIOCGUNIQ; +extern unsigned IOCTL_EVIOCGVERSION; +extern unsigned IOCTL_EVIOCRMFF; +extern unsigned IOCTL_EVIOCSABS; +extern unsigned IOCTL_EVIOCSFF; +extern unsigned IOCTL_EVIOCSKEYCODE; +extern unsigned IOCTL_EVIOCSREP; +extern unsigned IOCTL_BLKFLSBUF; +extern unsigned IOCTL_BLKGETSIZE; +extern unsigned IOCTL_BLKRAGET; +extern unsigned IOCTL_BLKRASET; +extern unsigned IOCTL_BLKROGET; +extern unsigned IOCTL_BLKROSET; +extern unsigned IOCTL_BLKRRPART; +extern unsigned IOCTL_CDROMAUDIOBUFSIZ; +extern unsigned IOCTL_CDROMEJECT; +extern unsigned IOCTL_CDROMEJECT_SW; +extern unsigned IOCTL_CDROMMULTISESSION; +extern unsigned IOCTL_CDROMPAUSE; +extern unsigned IOCTL_CDROMPLAYMSF; +extern unsigned IOCTL_CDROMPLAYTRKIND; +extern unsigned IOCTL_CDROMREADAUDIO; +extern unsigned IOCTL_CDROMREADCOOKED; +extern unsigned IOCTL_CDROMREADMODE1; +extern unsigned IOCTL_CDROMREADMODE2; +extern unsigned IOCTL_CDROMREADRAW; +extern unsigned IOCTL_CDROMREADTOCENTRY; +extern unsigned IOCTL_CDROMREADTOCHDR; +extern unsigned IOCTL_CDROMRESET; +extern unsigned IOCTL_CDROMRESUME; +extern unsigned IOCTL_CDROMSEEK; +extern unsigned IOCTL_CDROMSTART; +extern unsigned IOCTL_CDROMSTOP; +extern unsigned IOCTL_CDROMSUBCHNL; +extern unsigned IOCTL_CDROMVOLCTRL; +extern unsigned IOCTL_CDROMVOLREAD; +extern unsigned IOCTL_CDROM_GET_UPC; +extern unsigned IOCTL_FDCLRPRM; +extern unsigned IOCTL_FDDEFPRM; +extern unsigned IOCTL_FDFLUSH; +extern unsigned IOCTL_FDFMTBEG; +extern unsigned IOCTL_FDFMTEND; +extern unsigned IOCTL_FDFMTTRK; +extern unsigned IOCTL_FDGETDRVPRM; +extern unsigned IOCTL_FDGETDRVSTAT; +extern unsigned IOCTL_FDGETDRVTYP; +extern unsigned IOCTL_FDGETFDCSTAT; +extern unsigned IOCTL_FDGETMAXERRS; +extern unsigned IOCTL_FDGETPRM; +extern unsigned IOCTL_FDMSGOFF; +extern unsigned IOCTL_FDMSGON; +extern unsigned IOCTL_FDPOLLDRVSTAT; +extern unsigned IOCTL_FDRAWCMD; +extern unsigned IOCTL_FDRESET; +extern unsigned IOCTL_FDSETDRVPRM; +extern unsigned IOCTL_FDSETEMSGTRESH; +extern unsigned IOCTL_FDSETMAXERRS; +extern unsigned IOCTL_FDSETPRM; +extern unsigned IOCTL_FDTWADDLE; +extern unsigned IOCTL_FDWERRORCLR; +extern unsigned IOCTL_FDWERRORGET; +extern unsigned IOCTL_HDIO_DRIVE_CMD; +extern unsigned IOCTL_HDIO_GETGEO; +extern unsigned IOCTL_HDIO_GET_32BIT; +extern unsigned IOCTL_HDIO_GET_DMA; +extern unsigned IOCTL_HDIO_GET_IDENTITY; +extern unsigned IOCTL_HDIO_GET_KEEPSETTINGS; +extern unsigned IOCTL_HDIO_GET_MULTCOUNT; +extern unsigned IOCTL_HDIO_GET_NOWERR; +extern unsigned IOCTL_HDIO_GET_UNMASKINTR; +extern unsigned IOCTL_HDIO_SET_32BIT; +extern unsigned IOCTL_HDIO_SET_DMA; +extern unsigned IOCTL_HDIO_SET_KEEPSETTINGS; +extern unsigned IOCTL_HDIO_SET_MULTCOUNT; +extern unsigned IOCTL_HDIO_SET_NOWERR; +extern unsigned IOCTL_HDIO_SET_UNMASKINTR; +extern unsigned IOCTL_MTIOCPOS; +extern unsigned IOCTL_PPPIOCGASYNCMAP; +extern unsigned IOCTL_PPPIOCGDEBUG; +extern unsigned IOCTL_PPPIOCGFLAGS; +extern unsigned IOCTL_PPPIOCGUNIT; +extern unsigned IOCTL_PPPIOCGXASYNCMAP; +extern unsigned IOCTL_PPPIOCSASYNCMAP; +extern unsigned IOCTL_PPPIOCSDEBUG; +extern unsigned IOCTL_PPPIOCSFLAGS; +extern unsigned IOCTL_PPPIOCSMAXCID; +extern unsigned IOCTL_PPPIOCSMRU; +extern unsigned IOCTL_PPPIOCSXASYNCMAP; +extern unsigned IOCTL_SIOCDARP; +extern unsigned IOCTL_SIOCDRARP; +extern unsigned IOCTL_SIOCGARP; +extern unsigned IOCTL_SIOCGIFENCAP; +extern unsigned IOCTL_SIOCGIFHWADDR; +extern unsigned IOCTL_SIOCGIFMAP; +extern unsigned IOCTL_SIOCGIFMEM; +extern unsigned IOCTL_SIOCGIFNAME; +extern unsigned IOCTL_SIOCGIFSLAVE; +extern unsigned IOCTL_SIOCGRARP; +extern unsigned IOCTL_SIOCGSTAMP; +extern unsigned IOCTL_SIOCSARP; +extern unsigned IOCTL_SIOCSIFENCAP; +extern unsigned IOCTL_SIOCSIFHWADDR; +extern unsigned IOCTL_SIOCSIFLINK; +extern unsigned IOCTL_SIOCSIFMAP; +extern unsigned IOCTL_SIOCSIFMEM; +extern unsigned IOCTL_SIOCSIFSLAVE; +extern unsigned IOCTL_SIOCSRARP; +extern unsigned IOCTL_SNDCTL_COPR_HALT; +extern unsigned IOCTL_SNDCTL_COPR_LOAD; +extern unsigned IOCTL_SNDCTL_COPR_RCODE; +extern unsigned IOCTL_SNDCTL_COPR_RCVMSG; +extern unsigned IOCTL_SNDCTL_COPR_RDATA; +extern unsigned IOCTL_SNDCTL_COPR_RESET; +extern unsigned IOCTL_SNDCTL_COPR_RUN; +extern unsigned IOCTL_SNDCTL_COPR_SENDMSG; +extern unsigned IOCTL_SNDCTL_COPR_WCODE; +extern unsigned IOCTL_SNDCTL_COPR_WDATA; +extern unsigned IOCTL_TCFLSH; +extern unsigned IOCTL_TCGETA; +extern unsigned IOCTL_TCGETS; +extern unsigned IOCTL_TCSBRK; +extern unsigned IOCTL_TCSBRKP; +extern unsigned IOCTL_TCSETA; +extern unsigned IOCTL_TCSETAF; +extern unsigned IOCTL_TCSETAW; +extern unsigned IOCTL_TCSETS; +extern unsigned IOCTL_TCSETSF; +extern unsigned IOCTL_TCSETSW; +extern unsigned IOCTL_TCXONC; +extern unsigned IOCTL_TIOCGLCKTRMIOS; +extern unsigned IOCTL_TIOCGSOFTCAR; +extern unsigned IOCTL_TIOCINQ; +extern unsigned IOCTL_TIOCLINUX; +extern unsigned IOCTL_TIOCSERCONFIG; +extern unsigned IOCTL_TIOCSERGETLSR; +extern unsigned IOCTL_TIOCSERGWILD; +extern unsigned IOCTL_TIOCSERSWILD; +extern unsigned IOCTL_TIOCSLCKTRMIOS; +extern unsigned IOCTL_TIOCSSOFTCAR; +extern unsigned IOCTL_VT_DISALLOCATE; +extern unsigned IOCTL_VT_GETSTATE; +extern unsigned IOCTL_VT_RESIZE; +extern unsigned IOCTL_VT_RESIZEX; +extern unsigned IOCTL_VT_SENDSIG; +extern unsigned IOCTL_MTIOCGET; +extern unsigned IOCTL_MTIOCTOP; +extern unsigned IOCTL_SIOCADDRT; +extern unsigned IOCTL_SIOCDELRT; +extern unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE; +extern unsigned IOCTL_SNDCTL_DSP_GETFMTS; +extern unsigned IOCTL_SNDCTL_DSP_NONBLOCK; +extern unsigned IOCTL_SNDCTL_DSP_POST; +extern unsigned IOCTL_SNDCTL_DSP_RESET; +extern unsigned IOCTL_SNDCTL_DSP_SETFMT; +extern unsigned IOCTL_SNDCTL_DSP_SETFRAGMENT; +extern unsigned IOCTL_SNDCTL_DSP_SPEED; +extern unsigned IOCTL_SNDCTL_DSP_STEREO; +extern unsigned IOCTL_SNDCTL_DSP_SUBDIVIDE; +extern unsigned IOCTL_SNDCTL_DSP_SYNC; +extern unsigned IOCTL_SNDCTL_FM_4OP_ENABLE; +extern unsigned IOCTL_SNDCTL_FM_LOAD_INSTR; +extern unsigned IOCTL_SNDCTL_MIDI_INFO; +extern unsigned IOCTL_SNDCTL_MIDI_PRETIME; +extern unsigned IOCTL_SNDCTL_SEQ_CTRLRATE; +extern unsigned IOCTL_SNDCTL_SEQ_GETINCOUNT; +extern unsigned IOCTL_SNDCTL_SEQ_GETOUTCOUNT; +extern unsigned IOCTL_SNDCTL_SEQ_NRMIDIS; +extern unsigned IOCTL_SNDCTL_SEQ_NRSYNTHS; +extern unsigned IOCTL_SNDCTL_SEQ_OUTOFBAND; +extern unsigned IOCTL_SNDCTL_SEQ_PANIC; +extern unsigned IOCTL_SNDCTL_SEQ_PERCMODE; +extern unsigned IOCTL_SNDCTL_SEQ_RESET; +extern unsigned IOCTL_SNDCTL_SEQ_RESETSAMPLES; +extern unsigned IOCTL_SNDCTL_SEQ_SYNC; +extern unsigned IOCTL_SNDCTL_SEQ_TESTMIDI; +extern unsigned IOCTL_SNDCTL_SEQ_THRESHOLD; +extern unsigned IOCTL_SNDCTL_SYNTH_INFO; +extern unsigned IOCTL_SNDCTL_SYNTH_MEMAVL; +extern unsigned IOCTL_SNDCTL_TMR_CONTINUE; +extern unsigned IOCTL_SNDCTL_TMR_METRONOME; +extern unsigned IOCTL_SNDCTL_TMR_SELECT; +extern unsigned IOCTL_SNDCTL_TMR_SOURCE; +extern unsigned IOCTL_SNDCTL_TMR_START; +extern unsigned IOCTL_SNDCTL_TMR_STOP; +extern unsigned IOCTL_SNDCTL_TMR_TEMPO; +extern unsigned IOCTL_SNDCTL_TMR_TIMEBASE; +extern unsigned IOCTL_SOUND_MIXER_READ_ALTPCM; +extern unsigned IOCTL_SOUND_MIXER_READ_BASS; +extern unsigned IOCTL_SOUND_MIXER_READ_CAPS; +extern unsigned IOCTL_SOUND_MIXER_READ_CD; +extern unsigned IOCTL_SOUND_MIXER_READ_DEVMASK; +extern unsigned IOCTL_SOUND_MIXER_READ_ENHANCE; +extern unsigned IOCTL_SOUND_MIXER_READ_IGAIN; +extern unsigned IOCTL_SOUND_MIXER_READ_IMIX; +extern unsigned IOCTL_SOUND_MIXER_READ_LINE1; +extern unsigned IOCTL_SOUND_MIXER_READ_LINE2; +extern unsigned IOCTL_SOUND_MIXER_READ_LINE3; +extern unsigned IOCTL_SOUND_MIXER_READ_LINE; +extern unsigned IOCTL_SOUND_MIXER_READ_LOUD; +extern unsigned IOCTL_SOUND_MIXER_READ_MIC; +extern unsigned IOCTL_SOUND_MIXER_READ_MUTE; +extern unsigned IOCTL_SOUND_MIXER_READ_OGAIN; +extern unsigned IOCTL_SOUND_MIXER_READ_PCM; +extern unsigned IOCTL_SOUND_MIXER_READ_RECLEV; +extern unsigned IOCTL_SOUND_MIXER_READ_RECMASK; +extern unsigned IOCTL_SOUND_MIXER_READ_RECSRC; +extern unsigned IOCTL_SOUND_MIXER_READ_SPEAKER; +extern unsigned IOCTL_SOUND_MIXER_READ_STEREODEVS; +extern unsigned IOCTL_SOUND_MIXER_READ_SYNTH; +extern unsigned IOCTL_SOUND_MIXER_READ_TREBLE; +extern unsigned IOCTL_SOUND_MIXER_READ_VOLUME; +extern unsigned IOCTL_SOUND_MIXER_WRITE_ALTPCM; +extern unsigned IOCTL_SOUND_MIXER_WRITE_BASS; +extern unsigned IOCTL_SOUND_MIXER_WRITE_CD; +extern unsigned IOCTL_SOUND_MIXER_WRITE_ENHANCE; +extern unsigned IOCTL_SOUND_MIXER_WRITE_IGAIN; +extern unsigned IOCTL_SOUND_MIXER_WRITE_IMIX; +extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE1; +extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE2; +extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE3; +extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE; +extern unsigned IOCTL_SOUND_MIXER_WRITE_LOUD; +extern unsigned IOCTL_SOUND_MIXER_WRITE_MIC; +extern unsigned IOCTL_SOUND_MIXER_WRITE_MUTE; +extern unsigned IOCTL_SOUND_MIXER_WRITE_OGAIN; +extern unsigned IOCTL_SOUND_MIXER_WRITE_PCM; +extern unsigned IOCTL_SOUND_MIXER_WRITE_RECLEV; +extern unsigned IOCTL_SOUND_MIXER_WRITE_RECSRC; +extern unsigned IOCTL_SOUND_MIXER_WRITE_SPEAKER; +extern unsigned IOCTL_SOUND_MIXER_WRITE_SYNTH; +extern unsigned IOCTL_SOUND_MIXER_WRITE_TREBLE; +extern unsigned IOCTL_SOUND_MIXER_WRITE_VOLUME; +extern unsigned IOCTL_SOUND_PCM_READ_BITS; +extern unsigned IOCTL_SOUND_PCM_READ_CHANNELS; +extern unsigned IOCTL_SOUND_PCM_READ_FILTER; +extern unsigned IOCTL_SOUND_PCM_READ_RATE; +extern unsigned IOCTL_SOUND_PCM_WRITE_CHANNELS; +extern unsigned IOCTL_SOUND_PCM_WRITE_FILTER; +extern unsigned IOCTL_VT_ACTIVATE; +extern unsigned IOCTL_VT_GETMODE; +extern unsigned IOCTL_VT_OPENQRY; +extern unsigned IOCTL_VT_RELDISP; +extern unsigned IOCTL_VT_SETMODE; +extern unsigned IOCTL_VT_WAITACTIVE; #endif // SANITIZER_LINUX #if SANITIZER_LINUX && !SANITIZER_ANDROID - extern unsigned IOCTL_CYGETDEFTHRESH; - extern unsigned IOCTL_CYGETDEFTIMEOUT; - extern unsigned IOCTL_CYGETMON; - extern unsigned IOCTL_CYGETTHRESH; - extern unsigned IOCTL_CYGETTIMEOUT; - extern unsigned IOCTL_CYSETDEFTHRESH; - extern unsigned IOCTL_CYSETDEFTIMEOUT; - extern unsigned IOCTL_CYSETTHRESH; - extern unsigned IOCTL_CYSETTIMEOUT; - extern unsigned IOCTL_EQL_EMANCIPATE; - extern unsigned IOCTL_EQL_ENSLAVE; - extern unsigned IOCTL_EQL_GETMASTRCFG; - extern unsigned IOCTL_EQL_GETSLAVECFG; - extern unsigned IOCTL_EQL_SETMASTRCFG; - extern unsigned IOCTL_EQL_SETSLAVECFG; - extern unsigned IOCTL_EVIOCGKEYCODE_V2; - extern unsigned IOCTL_EVIOCGPROP; - extern unsigned IOCTL_EVIOCSKEYCODE_V2; - extern unsigned IOCTL_FS_IOC_GETFLAGS; - extern unsigned IOCTL_FS_IOC_GETVERSION; - extern unsigned IOCTL_FS_IOC_SETFLAGS; - extern unsigned IOCTL_FS_IOC_SETVERSION; - extern unsigned IOCTL_GIO_CMAP; - extern unsigned IOCTL_GIO_FONT; - extern unsigned IOCTL_GIO_UNIMAP; - extern unsigned IOCTL_GIO_UNISCRNMAP; - extern unsigned IOCTL_KDADDIO; - extern unsigned IOCTL_KDDELIO; - extern unsigned IOCTL_KDGETKEYCODE; - extern unsigned IOCTL_KDGKBDIACR; - extern unsigned IOCTL_KDGKBENT; - extern unsigned IOCTL_KDGKBLED; - extern unsigned IOCTL_KDGKBMETA; - extern unsigned IOCTL_KDGKBSENT; - extern unsigned IOCTL_KDMAPDISP; - extern unsigned IOCTL_KDSETKEYCODE; - extern unsigned IOCTL_KDSIGACCEPT; - extern unsigned IOCTL_KDSKBDIACR; - extern unsigned IOCTL_KDSKBENT; - extern unsigned IOCTL_KDSKBLED; - extern unsigned IOCTL_KDSKBMETA; - extern unsigned IOCTL_KDSKBSENT; - extern unsigned IOCTL_KDUNMAPDISP; - extern unsigned IOCTL_LPABORT; - extern unsigned IOCTL_LPABORTOPEN; - extern unsigned IOCTL_LPCAREFUL; - extern unsigned IOCTL_LPCHAR; - extern unsigned IOCTL_LPGETIRQ; - extern unsigned IOCTL_LPGETSTATUS; - extern unsigned IOCTL_LPRESET; - extern unsigned IOCTL_LPSETIRQ; - extern unsigned IOCTL_LPTIME; - extern unsigned IOCTL_LPWAIT; - extern unsigned IOCTL_MTIOCGETCONFIG; - extern unsigned IOCTL_MTIOCSETCONFIG; - extern unsigned IOCTL_PIO_CMAP; - extern unsigned IOCTL_PIO_FONT; - extern unsigned IOCTL_PIO_UNIMAP; - extern unsigned IOCTL_PIO_UNIMAPCLR; - extern unsigned IOCTL_PIO_UNISCRNMAP; - extern unsigned IOCTL_SCSI_IOCTL_GET_IDLUN; - extern unsigned IOCTL_SCSI_IOCTL_PROBE_HOST; - extern unsigned IOCTL_SCSI_IOCTL_TAGGED_DISABLE; - extern unsigned IOCTL_SCSI_IOCTL_TAGGED_ENABLE; - extern unsigned IOCTL_SIOCAIPXITFCRT; - extern unsigned IOCTL_SIOCAIPXPRISLT; - extern unsigned IOCTL_SIOCAX25ADDUID; - extern unsigned IOCTL_SIOCAX25DELUID; - extern unsigned IOCTL_SIOCAX25GETPARMS; - extern unsigned IOCTL_SIOCAX25GETUID; - extern unsigned IOCTL_SIOCAX25NOUID; - extern unsigned IOCTL_SIOCAX25SETPARMS; - extern unsigned IOCTL_SIOCDEVPLIP; - extern unsigned IOCTL_SIOCIPXCFGDATA; - extern unsigned IOCTL_SIOCNRDECOBS; - extern unsigned IOCTL_SIOCNRGETPARMS; - extern unsigned IOCTL_SIOCNRRTCTL; - extern unsigned IOCTL_SIOCNRSETPARMS; - extern unsigned IOCTL_SNDCTL_DSP_GETISPACE; - extern unsigned IOCTL_SNDCTL_DSP_GETOSPACE; - extern unsigned IOCTL_TIOCGSERIAL; - extern unsigned IOCTL_TIOCSERGETMULTI; - extern unsigned IOCTL_TIOCSERSETMULTI; - extern unsigned IOCTL_TIOCSSERIAL; - extern unsigned IOCTL_GIO_SCRNMAP; - extern unsigned IOCTL_KDDISABIO; - extern unsigned IOCTL_KDENABIO; - extern unsigned IOCTL_KDGETLED; - extern unsigned IOCTL_KDGETMODE; - extern unsigned IOCTL_KDGKBMODE; - extern unsigned IOCTL_KDGKBTYPE; - extern unsigned IOCTL_KDMKTONE; - extern unsigned IOCTL_KDSETLED; - extern unsigned IOCTL_KDSETMODE; - extern unsigned IOCTL_KDSKBMODE; - extern unsigned IOCTL_KIOCSOUND; - extern unsigned IOCTL_PIO_SCRNMAP; -#endif - - extern const int si_SEGV_MAPERR; - extern const int si_SEGV_ACCERR; +extern unsigned IOCTL_CYGETDEFTHRESH; +extern unsigned IOCTL_CYGETDEFTIMEOUT; +extern unsigned IOCTL_CYGETMON; +extern unsigned IOCTL_CYGETTHRESH; +extern unsigned IOCTL_CYGETTIMEOUT; +extern unsigned IOCTL_CYSETDEFTHRESH; +extern unsigned IOCTL_CYSETDEFTIMEOUT; +extern unsigned IOCTL_CYSETTHRESH; +extern unsigned IOCTL_CYSETTIMEOUT; +extern unsigned IOCTL_EQL_EMANCIPATE; +extern unsigned IOCTL_EQL_ENSLAVE; +extern unsigned IOCTL_EQL_GETMASTRCFG; +extern unsigned IOCTL_EQL_GETSLAVECFG; +extern unsigned IOCTL_EQL_SETMASTRCFG; +extern unsigned IOCTL_EQL_SETSLAVECFG; +extern unsigned IOCTL_EVIOCGKEYCODE_V2; +extern unsigned IOCTL_EVIOCGPROP; +extern unsigned IOCTL_EVIOCSKEYCODE_V2; +extern unsigned IOCTL_FS_IOC_GETFLAGS; +extern unsigned IOCTL_FS_IOC_GETVERSION; +extern unsigned IOCTL_FS_IOC_SETFLAGS; +extern unsigned IOCTL_FS_IOC_SETVERSION; +extern unsigned IOCTL_GIO_CMAP; +extern unsigned IOCTL_GIO_FONT; +extern unsigned IOCTL_GIO_UNIMAP; +extern unsigned IOCTL_GIO_UNISCRNMAP; +extern unsigned IOCTL_KDADDIO; +extern unsigned IOCTL_KDDELIO; +extern unsigned IOCTL_KDGETKEYCODE; +extern unsigned IOCTL_KDGKBDIACR; +extern unsigned IOCTL_KDGKBENT; +extern unsigned IOCTL_KDGKBLED; +extern unsigned IOCTL_KDGKBMETA; +extern unsigned IOCTL_KDGKBSENT; +extern unsigned IOCTL_KDMAPDISP; +extern unsigned IOCTL_KDSETKEYCODE; +extern unsigned IOCTL_KDSIGACCEPT; +extern unsigned IOCTL_KDSKBDIACR; +extern unsigned IOCTL_KDSKBENT; +extern unsigned IOCTL_KDSKBLED; +extern unsigned IOCTL_KDSKBMETA; +extern unsigned IOCTL_KDSKBSENT; +extern unsigned IOCTL_KDUNMAPDISP; +extern unsigned IOCTL_LPABORT; +extern unsigned IOCTL_LPABORTOPEN; +extern unsigned IOCTL_LPCAREFUL; +extern unsigned IOCTL_LPCHAR; +extern unsigned IOCTL_LPGETIRQ; +extern unsigned IOCTL_LPGETSTATUS; +extern unsigned IOCTL_LPRESET; +extern unsigned IOCTL_LPSETIRQ; +extern unsigned IOCTL_LPTIME; +extern unsigned IOCTL_LPWAIT; +extern unsigned IOCTL_MTIOCGETCONFIG; +extern unsigned IOCTL_MTIOCSETCONFIG; +extern unsigned IOCTL_PIO_CMAP; +extern unsigned IOCTL_PIO_FONT; +extern unsigned IOCTL_PIO_UNIMAP; +extern unsigned IOCTL_PIO_UNIMAPCLR; +extern unsigned IOCTL_PIO_UNISCRNMAP; +extern unsigned IOCTL_SCSI_IOCTL_GET_IDLUN; +extern unsigned IOCTL_SCSI_IOCTL_PROBE_HOST; +extern unsigned IOCTL_SCSI_IOCTL_TAGGED_DISABLE; +extern unsigned IOCTL_SCSI_IOCTL_TAGGED_ENABLE; +extern unsigned IOCTL_SIOCAIPXITFCRT; +extern unsigned IOCTL_SIOCAIPXPRISLT; +extern unsigned IOCTL_SIOCAX25ADDUID; +extern unsigned IOCTL_SIOCAX25DELUID; +extern unsigned IOCTL_SIOCAX25GETPARMS; +extern unsigned IOCTL_SIOCAX25GETUID; +extern unsigned IOCTL_SIOCAX25NOUID; +extern unsigned IOCTL_SIOCAX25SETPARMS; +extern unsigned IOCTL_SIOCDEVPLIP; +extern unsigned IOCTL_SIOCIPXCFGDATA; +extern unsigned IOCTL_SIOCNRDECOBS; +extern unsigned IOCTL_SIOCNRGETPARMS; +extern unsigned IOCTL_SIOCNRRTCTL; +extern unsigned IOCTL_SIOCNRSETPARMS; +extern unsigned IOCTL_SNDCTL_DSP_GETISPACE; +extern unsigned IOCTL_SNDCTL_DSP_GETOSPACE; +extern unsigned IOCTL_TIOCGSERIAL; +extern unsigned IOCTL_TIOCSERGETMULTI; +extern unsigned IOCTL_TIOCSERSETMULTI; +extern unsigned IOCTL_TIOCSSERIAL; +extern unsigned IOCTL_GIO_SCRNMAP; +extern unsigned IOCTL_KDDISABIO; +extern unsigned IOCTL_KDENABIO; +extern unsigned IOCTL_KDGETLED; +extern unsigned IOCTL_KDGETMODE; +extern unsigned IOCTL_KDGKBMODE; +extern unsigned IOCTL_KDGKBTYPE; +extern unsigned IOCTL_KDMKTONE; +extern unsigned IOCTL_KDSETLED; +extern unsigned IOCTL_KDSETMODE; +extern unsigned IOCTL_KDSKBMODE; +extern unsigned IOCTL_KIOCSOUND; +extern unsigned IOCTL_PIO_SCRNMAP; +#endif + +extern const int si_SEGV_MAPERR; +extern const int si_SEGV_ACCERR; } // namespace __sanitizer #define CHECK_TYPE_SIZE(TYPE) \ COMPILER_CHECK(sizeof(__sanitizer_##TYPE) == sizeof(TYPE)) -#define CHECK_SIZE_AND_OFFSET(CLASS, MEMBER) \ - COMPILER_CHECK(sizeof(((__sanitizer_##CLASS *) NULL)->MEMBER) == \ - sizeof(((CLASS *) NULL)->MEMBER)); \ - COMPILER_CHECK(offsetof(__sanitizer_##CLASS, MEMBER) == \ +#define CHECK_SIZE_AND_OFFSET(CLASS, MEMBER) \ + COMPILER_CHECK(sizeof(((__sanitizer_##CLASS *)NULL)->MEMBER) == \ + sizeof(((CLASS *)NULL)->MEMBER)); \ + COMPILER_CHECK(offsetof(__sanitizer_##CLASS, MEMBER) == \ offsetof(CLASS, MEMBER)) // For sigaction, which is a function and struct at the same time, // and thus requires explicit "struct" in sizeof() expression. -#define CHECK_STRUCT_SIZE_AND_OFFSET(CLASS, MEMBER) \ - COMPILER_CHECK(sizeof(((struct __sanitizer_##CLASS *) NULL)->MEMBER) == \ - sizeof(((struct CLASS *) NULL)->MEMBER)); \ - COMPILER_CHECK(offsetof(struct __sanitizer_##CLASS, MEMBER) == \ +#define CHECK_STRUCT_SIZE_AND_OFFSET(CLASS, MEMBER) \ + COMPILER_CHECK(sizeof(((struct __sanitizer_##CLASS *)NULL)->MEMBER) == \ + sizeof(((struct CLASS *)NULL)->MEMBER)); \ + COMPILER_CHECK(offsetof(struct __sanitizer_##CLASS, MEMBER) == \ offsetof(struct CLASS, MEMBER)) #define SIGACTION_SYMNAME sigaction diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_solaris.h b/libsanitizer/sanitizer_common/sanitizer_platform_limits_solaris.h index ed3b7a04dff..77ae6e6a44d 100644 --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_solaris.h +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_solaris.h @@ -68,7 +68,7 @@ struct __sanitizer_ipc_perm { #if !defined(_LP64) int pad[4]; #endif - }; +}; struct __sanitizer_shmid_ds { __sanitizer_ipc_perm shm_perm; @@ -237,9 +237,8 @@ typedef int __sanitizer_clockid_t; // This thing depends on the platform. We are only interested in the upper // limit. Verified with a compiler assert in .cpp. -const int pthread_attr_t_max_sz = 128; union __sanitizer_pthread_attr_t { - char size[pthread_attr_t_max_sz]; // NOLINT + char size[128]; void *align; }; diff --git a/libsanitizer/sanitizer_common/sanitizer_posix.cpp b/libsanitizer/sanitizer_common/sanitizer_posix.cpp index 002bcb1eda4..d890a3a3177 100644 --- a/libsanitizer/sanitizer_common/sanitizer_posix.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_posix.cpp @@ -312,6 +312,8 @@ const char *SignalContext::Describe() const { return "SEGV"; case SIGBUS: return "BUS"; + case SIGTRAP: + return "TRAP"; } return "UNKNOWN SIGNAL"; } diff --git a/libsanitizer/sanitizer_common/sanitizer_posix.h b/libsanitizer/sanitizer_common/sanitizer_posix.h index 6cf5ce75b12..05fb0f63020 100644 --- a/libsanitizer/sanitizer_common/sanitizer_posix.h +++ b/libsanitizer/sanitizer_common/sanitizer_posix.h @@ -63,7 +63,7 @@ uptr internal_ptrace(int request, int pid, void *addr, void *data); uptr internal_waitpid(int pid, int *status, int options); int internal_fork(); -int internal_forkpty(int *amaster); +fd_t internal_spawn(const char *argv[], pid_t *pid); int internal_sysctl(const int *name, unsigned int namelen, void *oldp, uptr *oldlenp, const void *newp, uptr newlen); diff --git a/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp index 1bbbf8a675f..304b3a01a08 100644 --- a/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp @@ -304,11 +304,13 @@ void PlatformPrepareForSandboxing(__sanitizer_sandbox_arguments *args) { MemoryMappingLayout::CacheMemoryMappings(); } -bool MmapFixedNoReserve(uptr fixed_addr, uptr size, const char *name) { +static bool MmapFixed(uptr fixed_addr, uptr size, int additional_flags, + const char *name) { size = RoundUpTo(size, GetPageSizeCached()); fixed_addr = RoundDownTo(fixed_addr, GetPageSizeCached()); - uptr p = MmapNamed((void *)fixed_addr, size, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_FIXED | MAP_NORESERVE | MAP_ANON, name); + uptr p = + MmapNamed((void *)fixed_addr, size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_FIXED | additional_flags | MAP_ANON, name); int reserrno; if (internal_iserror(p, &reserrno)) { Report("ERROR: %s failed to " @@ -320,6 +322,24 @@ bool MmapFixedNoReserve(uptr fixed_addr, uptr size, const char *name) { return true; } +bool MmapFixedNoReserve(uptr fixed_addr, uptr size, const char *name) { + return MmapFixed(fixed_addr, size, MAP_NORESERVE, name); +} + +bool MmapFixedSuperNoReserve(uptr fixed_addr, uptr size, const char *name) { +#if SANITIZER_FREEBSD + if (common_flags()->no_huge_pages_for_shadow) + return MmapFixedNoReserve(fixed_addr, size, name); + // MAP_NORESERVE is implicit with FreeBSD + return MmapFixed(fixed_addr, size, MAP_ALIGNED_SUPER, name); +#else + bool r = MmapFixedNoReserve(fixed_addr, size, name); + if (r) + SetShadowRegionHugePageMode(fixed_addr, size); + return r; +#endif +} + uptr ReservedAddressRange::Init(uptr size, const char *name, uptr fixed_addr) { base_ = fixed_addr ? MmapFixedNoAccess(fixed_addr, size, name) : MmapNoAccess(size); diff --git a/libsanitizer/sanitizer_common/sanitizer_printf.cpp b/libsanitizer/sanitizer_common/sanitizer_printf.cpp index 9d1c544786d..a032787114b 100644 --- a/libsanitizer/sanitizer_common/sanitizer_printf.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_printf.cpp @@ -229,15 +229,15 @@ void SetPrintfAndReportCallback(void (*callback)(const char *)) { // Can be overriden in frontend. #if SANITIZER_GO && defined(TSAN_EXTERNAL_HOOKS) // Implementation must be defined in frontend. -extern "C" void OnPrint(const char *str); +extern "C" void __sanitizer_on_print(const char *str); #else -SANITIZER_INTERFACE_WEAK_DEF(void, OnPrint, const char *str) { +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_on_print, const char *str) { (void)str; } #endif static void CallPrintfAndReportCallback(const char *str) { - OnPrint(str); + __sanitizer_on_print(str); if (PrintfAndReportCallback) PrintfAndReportCallback(str); } diff --git a/libsanitizer/sanitizer_common/sanitizer_procmaps.h b/libsanitizer/sanitizer_common/sanitizer_procmaps.h index 052027111ce..d0e5245f84d 100644 --- a/libsanitizer/sanitizer_common/sanitizer_procmaps.h +++ b/libsanitizer/sanitizer_common/sanitizer_procmaps.h @@ -37,7 +37,7 @@ struct MemoryMappedSegmentData; class MemoryMappedSegment { public: - MemoryMappedSegment(char *buff = nullptr, uptr size = 0) + explicit MemoryMappedSegment(char *buff = nullptr, uptr size = 0) : filename(buff), filename_size(size), data_(nullptr) {} ~MemoryMappedSegment() {} diff --git a/libsanitizer/sanitizer_common/sanitizer_procmaps_mac.cpp b/libsanitizer/sanitizer_common/sanitizer_procmaps_mac.cpp index ea72a57bf3c..d02afcfe87a 100644 --- a/libsanitizer/sanitizer_common/sanitizer_procmaps_mac.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_procmaps_mac.cpp @@ -181,13 +181,14 @@ const mach_header *get_dyld_hdr() { // Note that the segment addresses are not necessarily sorted. template static bool NextSegmentLoad(MemoryMappedSegment *segment, -MemoryMappedSegmentData *seg_data, MemoryMappingLayoutData &layout_data) { - const char *lc = layout_data.current_load_cmd_addr; - layout_data.current_load_cmd_addr += ((const load_command *)lc)->cmdsize; + MemoryMappedSegmentData *seg_data, + MemoryMappingLayoutData *layout_data) { + const char *lc = layout_data->current_load_cmd_addr; + layout_data->current_load_cmd_addr += ((const load_command *)lc)->cmdsize; if (((const load_command *)lc)->cmd == kLCSegment) { const SegmentCommand* sc = (const SegmentCommand *)lc; uptr base_virt_addr, addr_mask; - if (layout_data.current_image == kDyldImageIdx) { + if (layout_data->current_image == kDyldImageIdx) { base_virt_addr = (uptr)get_dyld_hdr(); // vmaddr is masked with 0xfffff because on macOS versions < 10.12, // it contains an absolute address rather than an offset for dyld. @@ -198,7 +199,7 @@ MemoryMappedSegmentData *seg_data, MemoryMappingLayoutData &layout_data) { addr_mask = 0xfffff; } else { base_virt_addr = - (uptr)_dyld_get_image_vmaddr_slide(layout_data.current_image); + (uptr)_dyld_get_image_vmaddr_slide(layout_data->current_image); addr_mask = ~0; } @@ -219,18 +220,18 @@ MemoryMappedSegmentData *seg_data, MemoryMappingLayoutData &layout_data) { // Return the initial protection. segment->protection = sc->initprot; - segment->offset = (layout_data.current_filetype == + segment->offset = (layout_data->current_filetype == /*MH_EXECUTE*/ 0x2) ? sc->vmaddr : sc->fileoff; if (segment->filename) { - const char *src = (layout_data.current_image == kDyldImageIdx) + const char *src = (layout_data->current_image == kDyldImageIdx) ? kDyldPath - : _dyld_get_image_name(layout_data.current_image); + : _dyld_get_image_name(layout_data->current_image); internal_strncpy(segment->filename, src, segment->filename_size); } - segment->arch = layout_data.current_arch; - internal_memcpy(segment->uuid, layout_data.current_uuid, kModuleUUIDSize); + segment->arch = layout_data->current_arch; + internal_memcpy(segment->uuid, layout_data->current_uuid, kModuleUUIDSize); return true; } return false; @@ -331,14 +332,14 @@ bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) { #ifdef MH_MAGIC_64 case MH_MAGIC_64: { if (NextSegmentLoad( - segment, segment->data_, data_)) + segment, segment->data_, &data_)) return true; break; } #endif case MH_MAGIC: { if (NextSegmentLoad( - segment, segment->data_, data_)) + segment, segment->data_, &data_)) return true; break; } diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp b/libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp index ce75cbe5d26..ef14fb704ee 100644 --- a/libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp @@ -60,8 +60,8 @@ static inline uhwptr *GetCanonicFrame(uptr bp, // Nope, this does not look right either. This means the frame after next does // not have a valid frame pointer, but we can still extract the caller PC. // Unfortunately, there is no way to decide between GCC and LLVM frame - // layouts. Assume GCC. - return bp_prev - 1; + // layouts. Assume LLVM. + return bp_prev; #else return (uhwptr*)bp; #endif @@ -84,21 +84,14 @@ void BufferedStackTrace::UnwindFast(uptr pc, uptr bp, uptr stack_top, IsAligned((uptr)frame, sizeof(*frame)) && size < max_depth) { #ifdef __powerpc__ - // PowerPC ABIs specify that the return address is saved on the - // *caller's* stack frame. Thus we must dereference the back chain - // to find the caller frame before extracting it. + // PowerPC ABIs specify that the return address is saved at offset + // 16 of the *caller's* stack frame. Thus we must dereference the + // back chain to find the caller frame before extracting it. uhwptr *caller_frame = (uhwptr*)frame[0]; if (!IsValidFrame((uptr)caller_frame, stack_top, bottom) || !IsAligned((uptr)caller_frame, sizeof(uhwptr))) break; - // For most ABIs the offset where the return address is saved is two - // register sizes. The exception is the SVR4 ABI, which uses an - // offset of only one register size. -#ifdef _CALL_SYSV - uhwptr pc1 = caller_frame[1]; -#else uhwptr pc1 = caller_frame[2]; -#endif #elif defined(__s390__) uhwptr pc1 = frame[14]; #else diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_stacktrace_libcdep.cpp index 2c08274f35c..4ef305cf179 100644 --- a/libsanitizer/sanitizer_common/sanitizer_stacktrace_libcdep.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace_libcdep.cpp @@ -150,8 +150,9 @@ void __sanitizer_symbolize_global(uptr data_addr, const char *fmt, } SANITIZER_INTERFACE_ATTRIBUTE -int __sanitizer_get_module_and_offset_for_pc( // NOLINT - uptr pc, char *module_name, uptr module_name_len, uptr *pc_offset) { +int __sanitizer_get_module_and_offset_for_pc(uptr pc, char *module_name, + uptr module_name_len, + uptr *pc_offset) { return __sanitizer::GetModuleAndOffsetForPc(pc, module_name, module_name_len, pc_offset); } diff --git a/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp index b520dc8daca..651d5056dd9 100644 --- a/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp @@ -223,10 +223,11 @@ bool ThreadSuspender::SuspendAllThreads() { case ThreadLister::Ok: break; } - for (tid_t tid : threads) + for (tid_t tid : threads) { if (SuspendThread(tid)) retry = true; - }; + } + } return suspended_threads_list_.ThreadCount(); } diff --git a/libsanitizer/sanitizer_common/sanitizer_suppressions.h b/libsanitizer/sanitizer_common/sanitizer_suppressions.h index f9da7af7e6a..2d88b1f72fa 100644 --- a/libsanitizer/sanitizer_common/sanitizer_suppressions.h +++ b/libsanitizer/sanitizer_common/sanitizer_suppressions.h @@ -42,7 +42,7 @@ class SuppressionContext { void GetMatched(InternalMmapVector *matched); private: - static const int kMaxSuppressionTypes = 32; + static const int kMaxSuppressionTypes = 64; const char **const suppression_types_; const int suppression_types_num_; diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_internal.h b/libsanitizer/sanitizer_common/sanitizer_symbolizer_internal.h index 3031f28a20e..c04797dd61b 100644 --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_internal.h +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_internal.h @@ -76,7 +76,7 @@ class SymbolizerTool { // SymbolizerProcess may not be used from two threads simultaneously. class SymbolizerProcess { public: - explicit SymbolizerProcess(const char *path, bool use_forkpty = false); + explicit SymbolizerProcess(const char *path, bool use_posix_spawn = false); const char *SendCommand(const char *command); protected: @@ -114,7 +114,7 @@ class SymbolizerProcess { uptr times_restarted_; bool failed_to_start_; bool reported_invalid_path_; - bool use_forkpty_; + bool use_posix_spawn_; }; class LLVMSymbolizerProcess; diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cpp index 742b9748c98..3b19a6836ec 100644 --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cpp @@ -238,7 +238,8 @@ const LoadedModule *Symbolizer::FindModuleForAddress(uptr address) { // class LLVMSymbolizerProcess : public SymbolizerProcess { public: - explicit LLVMSymbolizerProcess(const char *path) : SymbolizerProcess(path) {} + explicit LLVMSymbolizerProcess(const char *path) + : SymbolizerProcess(path, /*use_posix_spawn=*/SANITIZER_MAC) {} private: bool ReachedEndOfOutput(const char *buffer, uptr length) const override { @@ -452,14 +453,14 @@ const char *LLVMSymbolizer::FormatAndSendCommand(const char *command_prefix, return symbolizer_process_->SendCommand(buffer_); } -SymbolizerProcess::SymbolizerProcess(const char *path, bool use_forkpty) +SymbolizerProcess::SymbolizerProcess(const char *path, bool use_posix_spawn) : path_(path), input_fd_(kInvalidFd), output_fd_(kInvalidFd), times_restarted_(0), failed_to_start_(false), reported_invalid_path_(false), - use_forkpty_(use_forkpty) { + use_posix_spawn_(use_posix_spawn) { CHECK(path_); CHECK_NE(path_[0], '\0'); } diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.cpp index 7bc4b0ce025..a619ed092f0 100644 --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.cpp @@ -50,14 +50,14 @@ bool DlAddrSymbolizer::SymbolizeData(uptr addr, DataInfo *datainfo) { class AtosSymbolizerProcess : public SymbolizerProcess { public: explicit AtosSymbolizerProcess(const char *path, pid_t parent_pid) - : SymbolizerProcess(path, /*use_forkpty*/ true) { + : SymbolizerProcess(path, /*use_posix_spawn*/ true) { // Put the string command line argument in the object so that it outlives // the call to GetArgV. internal_snprintf(pid_str_, sizeof(pid_str_), "%d", parent_pid); } private: - virtual bool StartSymbolizerSubprocess() override { + bool StartSymbolizerSubprocess() override { // Configure sandbox before starting atos process. return SymbolizerProcess::StartSymbolizerSubprocess(); } diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp index 43e6a6d2dbf..c123ecb1120 100644 --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp @@ -33,10 +33,6 @@ #include #include -#if SANITIZER_MAC -#include // for forkpty() -#endif // SANITIZER_MAC - // C++ demangling function, as required by Itanium C++ ABI. This is weak, // 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. @@ -151,80 +147,32 @@ bool SymbolizerProcess::StartSymbolizerSubprocess() { return false; } - int pid = -1; - - int infd[2]; - internal_memset(&infd, 0, sizeof(infd)); - int outfd[2]; - internal_memset(&outfd, 0, sizeof(outfd)); - if (!CreateTwoHighNumberedPipes(infd, outfd)) { - Report("WARNING: Can't create a socket pair to start " - "external symbolizer (errno: %d)\n", errno); - return false; - } + const char *argv[kArgVMax]; + GetArgV(path_, argv); + pid_t pid; - if (use_forkpty_) { + if (use_posix_spawn_) { #if SANITIZER_MAC - fd_t fd = kInvalidFd; - - // forkpty redirects stdout and stderr into a single stream, so we would - // receive error messages as standard replies. To avoid that, let's dup - // stderr and restore it in the child. - int saved_stderr = dup(STDERR_FILENO); - CHECK_GE(saved_stderr, 0); - - // We only need one pipe, for stdin of the child. - close(outfd[0]); - close(outfd[1]); - - // Use forkpty to disable buffering in the new terminal. - pid = internal_forkpty(&fd); - if (pid == -1) { - // forkpty() failed. - Report("WARNING: failed to fork external symbolizer (errno: %d)\n", + fd_t fd = internal_spawn(argv, &pid); + if (fd == kInvalidFd) { + Report("WARNING: failed to spawn external symbolizer (errno: %d)\n", errno); return false; - } else if (pid == 0) { - // Child subprocess. - - // infd[0] is the child's reading end. - close(infd[1]); - - // Set up stdin to read from the pipe. - CHECK_GE(dup2(infd[0], STDIN_FILENO), 0); - close(infd[0]); - - // Restore stderr. - CHECK_GE(dup2(saved_stderr, STDERR_FILENO), 0); - close(saved_stderr); - - const char *argv[kArgVMax]; - GetArgV(path_, argv); - execv(path_, const_cast(&argv[0])); - internal__exit(1); } - // Input for the child, infd[1] is our writing end. - output_fd_ = infd[1]; - close(infd[0]); - - // Continue execution in parent process. input_fd_ = fd; - - close(saved_stderr); - - // Disable echo in the new terminal, disable CR. - struct termios termflags; - tcgetattr(fd, &termflags); - termflags.c_oflag &= ~ONLCR; - termflags.c_lflag &= ~ECHO; - tcsetattr(fd, TCSANOW, &termflags); + output_fd_ = fd; #else // SANITIZER_MAC UNIMPLEMENTED(); #endif // SANITIZER_MAC } else { - const char *argv[kArgVMax]; - GetArgV(path_, argv); + 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); + return false; + } + pid = StartSubprocess(path_, argv, /* stdin */ outfd[0], /* stdout */ infd[1]); if (pid < 0) { diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_report.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_report.cpp index a8b449b030e..c26724ceb7a 100644 --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_report.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_report.cpp @@ -106,8 +106,9 @@ void ReportMmapWriteExec(int prot) { if (StackTrace::WillUseFastUnwind(fast)) { GetThreadStackTopAndBottom(false, &top, &bottom); stack->Unwind(kStackTraceMax, pc, bp, nullptr, top, bottom, true); - } else + } else { stack->Unwind(kStackTraceMax, pc, 0, nullptr, 0, 0, false); + } Printf("%s", d.Warning()); Report("WARNING: %s: writable-executable page usage\n", SanitizerToolName); @@ -190,9 +191,14 @@ static void ReportDeadlySignalImpl(const SignalContext &sig, u32 tid, SanitizerCommonDecorator d; Printf("%s", d.Warning()); const char *description = sig.Describe(); - Report("ERROR: %s: %s on unknown address %p (pc %p bp %p sp %p T%d)\n", - SanitizerToolName, description, (void *)sig.addr, (void *)sig.pc, - (void *)sig.bp, (void *)sig.sp, tid); + if (sig.is_memory_access && !sig.is_true_faulting_addr) + Report("ERROR: %s: %s on unknown address (pc %p bp %p sp %p T%d)\n", + SanitizerToolName, description, (void *)sig.pc, (void *)sig.bp, + (void *)sig.sp, tid); + else + Report("ERROR: %s: %s on unknown address %p (pc %p bp %p sp %p T%d)\n", + SanitizerToolName, description, (void *)sig.addr, (void *)sig.pc, + (void *)sig.bp, (void *)sig.sp, tid); Printf("%s", d.Default()); if (sig.pc < GetPageSizeCached()) Report("Hint: pc points to the zero page.\n"); @@ -202,7 +208,11 @@ static void ReportDeadlySignalImpl(const SignalContext &sig, u32 tid, ? "WRITE" : (sig.write_flag == SignalContext::READ ? "READ" : "UNKNOWN"); Report("The signal is caused by a %s memory access.\n", access_type); - if (sig.addr < GetPageSizeCached()) + if (!sig.is_true_faulting_addr) + Report("Hint: this fault was caused by a dereference of a high value " + "address (see register values below). Dissassemble the provided " + "pc to learn which register was used.\n"); + else if (sig.addr < GetPageSizeCached()) Report("Hint: address points to the zero page.\n"); } MaybeReportNonExecRegion(sig.pc); diff --git a/libsanitizer/sanitizer_common/sanitizer_termination.cpp b/libsanitizer/sanitizer_common/sanitizer_termination.cpp index e588c93b994..84be6fc3234 100644 --- a/libsanitizer/sanitizer_common/sanitizer_termination.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_termination.cpp @@ -84,7 +84,7 @@ void NORETURN CheckFailed(const char *file, int line, const char *cond, } // namespace __sanitizer -using namespace __sanitizer; // NOLINT +using namespace __sanitizer; extern "C" { SANITIZER_INTERFACE_ATTRIBUTE diff --git a/libsanitizer/sanitizer_common/sanitizer_unwind_linux_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_unwind_linux_libcdep.cpp index 1a43759e38a..b2628dcc4dc 100644 --- a/libsanitizer/sanitizer_common/sanitizer_unwind_linux_libcdep.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_unwind_linux_libcdep.cpp @@ -27,6 +27,8 @@ namespace __sanitizer { +namespace { + //---------------------------- UnwindSlow -------------------------------------- typedef struct { @@ -46,38 +48,6 @@ release_my_map_info_list_func release_my_map_info_list; unwind_backtrace_signal_arch_func unwind_backtrace_signal_arch; } // extern "C" -#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 - #if defined(__arm__) && !SANITIZER_NETBSD // NetBSD uses dwarf EH #define UNWIND_STOP _URC_END_OF_STACK @@ -119,6 +89,40 @@ _Unwind_Reason_Code Unwind_Trace(struct _Unwind_Context *ctx, void *param) { return UNWIND_CONTINUE; } +} // 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; diff --git a/libsanitizer/sanitizer_common/sanitizer_vector.h b/libsanitizer/sanitizer_common/sanitizer_vector.h index 4b9ae7db4c1..31216f3ec3a 100644 --- a/libsanitizer/sanitizer_common/sanitizer_vector.h +++ b/libsanitizer/sanitizer_common/sanitizer_vector.h @@ -23,11 +23,7 @@ namespace __sanitizer { template class Vector { public: - explicit Vector() - : begin_() - , end_() - , last_() { - } + Vector() : begin_(), end_(), last_() {} ~Vector() { if (begin_) diff --git a/libsanitizer/sanitizer_common/sanitizer_win.cpp b/libsanitizer/sanitizer_common/sanitizer_win.cpp index c98e3d42f43..36dde49d870 100644 --- a/libsanitizer/sanitizer_common/sanitizer_win.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_win.cpp @@ -239,6 +239,11 @@ bool MmapFixedNoReserve(uptr fixed_addr, uptr size, const char *name) { return true; } +bool MmapFixedSuperNoReserve(uptr fixed_addr, uptr size, const char *name) { + // FIXME: Windows support large pages too. Might be worth checking + return MmapFixedNoReserve(fixed_addr, size, name); +} + // Memory space mapped by 'MmapFixedOrDie' must have been reserved by // 'MmapFixedNoAccess'. void *MmapFixedOrDie(uptr fixed_addr, uptr size, const char *name) { @@ -671,7 +676,7 @@ static int RunAtexit() { return ret; } -#pragma section(".CRT$XID", long, read) // NOLINT +#pragma section(".CRT$XID", long, read) __declspec(allocate(".CRT$XID")) int (*__run_atexit)() = RunAtexit; #endif @@ -940,6 +945,11 @@ bool SignalContext::IsMemoryAccess() const { return GetWriteFlag() != SignalContext::UNKNOWN; } +bool SignalContext::IsTrueFaultingAddress() const { + // FIXME: Provide real implementation for this. See Linux and Mac variants. + return IsMemoryAccess(); +} + SignalContext::WriteFlag SignalContext::GetWriteFlag() const { EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD *)siginfo; // The contents of this array are documented at diff --git a/libsanitizer/sanitizer_common/sanitizer_win_defs.h b/libsanitizer/sanitizer_common/sanitizer_win_defs.h index bcd94a08dc4..bfe38a33236 100644 --- a/libsanitizer/sanitizer_common/sanitizer_win_defs.h +++ b/libsanitizer/sanitizer_common/sanitizer_win_defs.h @@ -43,6 +43,8 @@ #define STRINGIFY_(A) #A #define STRINGIFY(A) STRINGIFY_(A) +#if !SANITIZER_GO + // ----------------- A workaround for the absence of weak symbols -------------- // We don't have a direct equivalent of weak symbols when using MSVC, but we can // use the /alternatename directive to tell the linker to default a specific @@ -158,5 +160,15 @@ // return a >= b; // } // + +#else // SANITIZER_GO + +// Go neither needs nor wants weak references. +// The shenanigans above don't work for gcc. +# define WIN_WEAK_EXPORT_DEF(ReturnType, Name, ...) \ + extern "C" ReturnType Name(__VA_ARGS__) + +#endif // SANITIZER_GO + #endif // SANITIZER_WINDOWS #endif // SANITIZER_WIN_DEFS_H diff --git a/libsanitizer/sanitizer_common/sanitizer_win_dll_thunk.cpp b/libsanitizer/sanitizer_common/sanitizer_win_dll_thunk.cpp index aa0eb4d43a4..1562c161a76 100644 --- a/libsanitizer/sanitizer_common/sanitizer_win_dll_thunk.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_win_dll_thunk.cpp @@ -54,8 +54,8 @@ int dllThunkInterceptWhenPossible(const char* main_function, #define INTERFACE_WEAK_FUNCTION(Name) INTERCEPT_SANITIZER_WEAK_FUNCTION(Name) #include "sanitizer_common_interface.inc" -#pragma section(".DLLTH$A", read) // NOLINT -#pragma section(".DLLTH$Z", read) // NOLINT +#pragma section(".DLLTH$A", read) +#pragma section(".DLLTH$Z", read) typedef void (*DllThunkCB)(); extern "C" { @@ -85,7 +85,7 @@ extern "C" int __dll_thunk_init() { // We want to call dll_thunk_init before C/C++ initializers / constructors are // executed, otherwise functions like memset might be invoked. -#pragma section(".CRT$XIB", long, read) // NOLINT +#pragma section(".CRT$XIB", long, read) __declspec(allocate(".CRT$XIB")) int (*__dll_thunk_preinit)() = __dll_thunk_init; @@ -94,7 +94,7 @@ static void WINAPI dll_thunk_thread_init(void *mod, unsigned long reason, if (reason == /*DLL_PROCESS_ATTACH=*/1) __dll_thunk_init(); } -#pragma section(".CRT$XLAB", long, read) // NOLINT +#pragma section(".CRT$XLAB", long, read) __declspec(allocate(".CRT$XLAB")) void (WINAPI *__dll_thunk_tls_init)(void *, unsigned long, void *) = dll_thunk_thread_init; diff --git a/libsanitizer/sanitizer_common/sanitizer_win_weak_interception.cpp b/libsanitizer/sanitizer_common/sanitizer_win_weak_interception.cpp index a6f34c27788..b14bbf76d9a 100644 --- a/libsanitizer/sanitizer_common/sanitizer_win_weak_interception.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_win_weak_interception.cpp @@ -38,6 +38,7 @@ int interceptWhenPossible(uptr dll_function, const char *real_function) { // Declare weak hooks. extern "C" { +void __sanitizer_on_print(const char *str); void __sanitizer_weak_hook_memcmp(uptr called_pc, const void *s1, const void *s2, uptr n, int result); void __sanitizer_weak_hook_strcmp(uptr called_pc, const char *s1, @@ -53,8 +54,8 @@ void __sanitizer_weak_hook_strstr(uptr called_pc, const char *s1, #define INTERFACE_WEAK_FUNCTION(Name) INTERCEPT_SANITIZER_WEAK_FUNCTION(Name) #include "sanitizer_common_interface.inc" -#pragma section(".WEAK$A", read) // NOLINT -#pragma section(".WEAK$Z", read) // NOLINT +#pragma section(".WEAK$A", read) +#pragma section(".WEAK$Z", read) typedef void (*InterceptCB)(); extern "C" { @@ -77,7 +78,7 @@ static int weak_intercept_init() { return 0; } -#pragma section(".CRT$XIB", long, read) // NOLINT +#pragma section(".CRT$XIB", long, read) __declspec(allocate(".CRT$XIB")) int (*__weak_intercept_preinit)() = weak_intercept_init; @@ -86,7 +87,7 @@ static void WINAPI weak_intercept_thread_init(void *mod, unsigned long reason, if (reason == /*DLL_PROCESS_ATTACH=*/1) weak_intercept_init(); } -#pragma section(".CRT$XLAB", long, read) // NOLINT +#pragma section(".CRT$XLAB", long, read) __declspec(allocate(".CRT$XLAB")) void(WINAPI *__weak_intercept_tls_init)( void *, unsigned long, void *) = weak_intercept_thread_init; diff --git a/libsanitizer/tsan/tsan_dispatch_defs.h b/libsanitizer/tsan/tsan_dispatch_defs.h index 6f1d1f75f60..298297af31e 100644 --- a/libsanitizer/tsan/tsan_dispatch_defs.h +++ b/libsanitizer/tsan/tsan_dispatch_defs.h @@ -31,11 +31,11 @@ typedef void (^dispatch_block_t)(void); typedef void (^dispatch_io_handler_t)(bool done, dispatch_data_t data, int error); -typedef long dispatch_once_t; // NOLINT +typedef long dispatch_once_t; typedef __sanitizer::u64 dispatch_time_t; -typedef int dispatch_fd_t; // NOLINT -typedef unsigned long dispatch_io_type_t; // NOLINT -typedef unsigned long dispatch_io_close_flags_t; // NOLINT +typedef int dispatch_fd_t; +typedef unsigned long dispatch_io_type_t; +typedef unsigned long dispatch_io_close_flags_t; extern "C" { void *dispatch_get_context(dispatch_object_t object); @@ -57,10 +57,10 @@ extern const dispatch_block_t _dispatch_data_destructor_munmap; #endif // Data types used in dispatch APIs -typedef unsigned long size_t; // NOLINT -typedef unsigned long uintptr_t; // NOLINT +typedef unsigned long size_t; +typedef unsigned long uintptr_t; typedef __sanitizer::s64 off_t; typedef __sanitizer::u16 mode_t; -typedef long long_t; // NOLINT +typedef long long_t; #endif // TSAN_DISPATCH_DEFS_H diff --git a/libsanitizer/tsan/tsan_external.cpp b/libsanitizer/tsan/tsan_external.cpp index efc1013087c..0faa1ee93a1 100644 --- a/libsanitizer/tsan/tsan_external.cpp +++ b/libsanitizer/tsan/tsan_external.cpp @@ -25,7 +25,7 @@ static TagData registered_tags[kExternalTagMax] = { {}, {"Swift variable", "Swift access race"}, }; -static atomic_uint32_t used_tags{kExternalTagFirstUserAvailable}; // NOLINT. +static atomic_uint32_t used_tags{kExternalTagFirstUserAvailable}; static TagData *GetTagData(uptr tag) { // Invalid/corrupted tag? Better return NULL and let the caller deal with it. if (tag >= atomic_load(&used_tags, memory_order_relaxed)) return nullptr; diff --git a/libsanitizer/tsan/tsan_fd.cpp b/libsanitizer/tsan/tsan_fd.cpp index db01d809531..50a6b56916a 100644 --- a/libsanitizer/tsan/tsan_fd.cpp +++ b/libsanitizer/tsan/tsan_fd.cpp @@ -86,7 +86,8 @@ static FdDesc *fddesc(ThreadState *thr, uptr pc, int fd) { else user_free(thr, pc, p, false); } - return &((FdDesc*)l1)[fd % kTableSizeL2]; // NOLINT + FdDesc *fds = reinterpret_cast(l1); + return &fds[fd % kTableSizeL2]; } // pd must be already ref'ed. diff --git a/libsanitizer/tsan/tsan_interceptors.cpp b/libsanitizer/tsan/tsan_interceptors.cpp deleted file mode 100644 index 9e1b9ed77be..00000000000 --- a/libsanitizer/tsan/tsan_interceptors.cpp +++ /dev/null @@ -1,2855 +0,0 @@ -//===-- tsan_interceptors.cpp ---------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file is a part of ThreadSanitizer (TSan), a race detector. -// -// FIXME: move as many interceptors as possible into -// sanitizer_common/sanitizer_common_interceptors.inc -//===----------------------------------------------------------------------===// - -#include "sanitizer_common/sanitizer_atomic.h" -#include "sanitizer_common/sanitizer_errno.h" -#include "sanitizer_common/sanitizer_libc.h" -#include "sanitizer_common/sanitizer_linux.h" -#include "sanitizer_common/sanitizer_platform_limits_netbsd.h" -#include "sanitizer_common/sanitizer_platform_limits_posix.h" -#include "sanitizer_common/sanitizer_placement_new.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 "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" - - -using namespace __tsan; // NOLINT - -#if SANITIZER_FREEBSD || SANITIZER_MAC -#define stdout __stdoutp -#define stderr __stderrp -#endif - -#if SANITIZER_NETBSD -#define dirfd(dirp) (*(int *)(dirp)) -#define fileno_unlocked(fp) \ - (((__sanitizer_FILE*)fp)->_file == -1 ? -1 : \ - (int)(unsigned short)(((__sanitizer_FILE*)fp)->_file)) // NOLINT - -#define stdout ((__sanitizer_FILE*)&__sF[1]) -#define stderr ((__sanitizer_FILE*)&__sF[2]) - -#define nanosleep __nanosleep50 -#define vfork __vfork14 -#endif - -#if SANITIZER_ANDROID -#define mallopt(a, b) -#endif - -#ifdef __mips__ -const int kSigCount = 129; -#else -const int kSigCount = 65; -#endif - -#ifdef __mips__ -struct ucontext_t { - u64 opaque[768 / sizeof(u64) + 1]; -}; -#else -struct ucontext_t { - // The size is determined by looking at sizeof of real ucontext_t on linux. - u64 opaque[936 / sizeof(u64) + 1]; -}; -#endif - -#if defined(__x86_64__) || defined(__mips__) || SANITIZER_PPC64V1 -#define PTHREAD_ABI_BASE "GLIBC_2.3.2" -#elif defined(__aarch64__) || SANITIZER_PPC64V2 -#define PTHREAD_ABI_BASE "GLIBC_2.17" -#endif - -extern "C" int pthread_attr_init(void *attr); -extern "C" int pthread_attr_destroy(void *attr); -DECLARE_REAL(int, pthread_attr_getdetachstate, void *, void *) -extern "C" int pthread_attr_setstacksize(void *attr, uptr stacksize); -extern "C" int pthread_key_create(unsigned *key, void (*destructor)(void* v)); -extern "C" int pthread_setspecific(unsigned key, const void *v); -DECLARE_REAL(int, pthread_mutexattr_gettype, void *, void *) -DECLARE_REAL(int, fflush, __sanitizer_FILE *fp) -DECLARE_REAL_AND_INTERCEPTOR(void *, malloc, uptr size) -DECLARE_REAL_AND_INTERCEPTOR(void, free, void *ptr) -extern "C" void *pthread_self(); -extern "C" void _exit(int status); -#if !SANITIZER_NETBSD -extern "C" int fileno_unlocked(void *stream); -extern "C" int dirfd(void *dirp); -#endif -#if !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_NETBSD -extern "C" int mallopt(int param, int value); -#endif -#if SANITIZER_NETBSD -extern __sanitizer_FILE __sF[]; -#else -extern __sanitizer_FILE *stdout, *stderr; -#endif -#if !SANITIZER_FREEBSD && !SANITIZER_MAC && !SANITIZER_NETBSD -const int PTHREAD_MUTEX_RECURSIVE = 1; -const int PTHREAD_MUTEX_RECURSIVE_NP = 1; -#else -const int PTHREAD_MUTEX_RECURSIVE = 2; -const int PTHREAD_MUTEX_RECURSIVE_NP = 2; -#endif -#if !SANITIZER_FREEBSD && !SANITIZER_MAC && !SANITIZER_NETBSD -const int EPOLL_CTL_ADD = 1; -#endif -const int SIGILL = 4; -const int SIGABRT = 6; -const int SIGFPE = 8; -const int SIGSEGV = 11; -const int SIGPIPE = 13; -const int SIGTERM = 15; -#if defined(__mips__) || SANITIZER_FREEBSD || SANITIZER_MAC || SANITIZER_NETBSD -const int SIGBUS = 10; -const int SIGSYS = 12; -#else -const int SIGBUS = 7; -const int SIGSYS = 31; -#endif -void *const MAP_FAILED = (void*)-1; -#if SANITIZER_NETBSD -const int PTHREAD_BARRIER_SERIAL_THREAD = 1234567; -#elif !SANITIZER_MAC -const int PTHREAD_BARRIER_SERIAL_THREAD = -1; -#endif -const int MAP_FIXED = 0x10; -typedef long long_t; // NOLINT - -// From /usr/include/unistd.h -# define F_ULOCK 0 /* Unlock a previously locked region. */ -# define F_LOCK 1 /* Lock a region for exclusive use. */ -# define F_TLOCK 2 /* Test and lock a region for exclusive use. */ -# define F_TEST 3 /* Test a region for other processes locks. */ - -#if SANITIZER_FREEBSD || SANITIZER_MAC || SANITIZER_NETBSD -const int SA_SIGINFO = 0x40; -const int SIG_SETMASK = 3; -#elif defined(__mips__) -const int SA_SIGINFO = 8; -const int SIG_SETMASK = 3; -#else -const int SA_SIGINFO = 4; -const int SIG_SETMASK = 2; -#endif - -#define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED \ - (cur_thread_init(), !cur_thread()->is_inited) - -namespace __tsan { -struct SignalDesc { - bool armed; - bool sigaction; - __sanitizer_siginfo siginfo; - ucontext_t ctx; -}; - -struct ThreadSignalContext { - int int_signal_send; - atomic_uintptr_t in_blocking_func; - atomic_uintptr_t have_pending_signals; - SignalDesc pending_signals[kSigCount]; - // emptyset and oldset are too big for stack. - __sanitizer_sigset_t emptyset; - __sanitizer_sigset_t oldset; -}; - -// The sole reason tsan wraps atexit callbacks is to establish synchronization -// between callback setup and callback execution. -struct AtExitCtx { - void (*f)(); - void *arg; -}; - -// InterceptorContext holds all global data required for interceptors. -// It's explicitly constructed in InitializeInterceptors with placement new -// and is never destroyed. This allows usage of members with non-trivial -// constructors and destructors. -struct InterceptorContext { - // The object is 64-byte aligned, because we want hot data to be located - // in a single cache line if possible (it's accessed in every interceptor). - ALIGNED(64) LibIgnore libignore; - __sanitizer_sigaction sigactions[kSigCount]; -#if !SANITIZER_MAC && !SANITIZER_NETBSD - unsigned finalize_key; -#endif - - BlockingMutex atexit_mu; - Vector AtExitStack; - - InterceptorContext() - : libignore(LINKER_INITIALIZED), AtExitStack() { - } -}; - -static ALIGNED(64) char interceptor_placeholder[sizeof(InterceptorContext)]; -InterceptorContext *interceptor_ctx() { - return reinterpret_cast(&interceptor_placeholder[0]); -} - -LibIgnore *libignore() { - return &interceptor_ctx()->libignore; -} - -void InitializeLibIgnore() { - const SuppressionContext &supp = *Suppressions(); - const uptr n = supp.SuppressionCount(); - for (uptr i = 0; i < n; i++) { - const Suppression *s = supp.SuppressionAt(i); - if (0 == internal_strcmp(s->type, kSuppressionLib)) - libignore()->AddIgnoredLibrary(s->templ); - } - if (flags()->ignore_noninstrumented_modules) - libignore()->IgnoreNoninstrumentedModules(true); - libignore()->OnLibraryLoaded(0); -} - -// The following two hooks can be used by for cooperative scheduling when -// locking. -#ifdef TSAN_EXTERNAL_HOOKS -void OnPotentiallyBlockingRegionBegin(); -void OnPotentiallyBlockingRegionEnd(); -#else -SANITIZER_WEAK_CXX_DEFAULT_IMPL void OnPotentiallyBlockingRegionBegin() {} -SANITIZER_WEAK_CXX_DEFAULT_IMPL void OnPotentiallyBlockingRegionEnd() {} -#endif - -} // namespace __tsan - -static ThreadSignalContext *SigCtx(ThreadState *thr) { - ThreadSignalContext *ctx = (ThreadSignalContext*)thr->signal_ctx; - if (ctx == 0 && !thr->is_dead) { - ctx = (ThreadSignalContext*)MmapOrDie(sizeof(*ctx), "ThreadSignalContext"); - MemoryResetRange(thr, (uptr)&SigCtx, (uptr)ctx, sizeof(*ctx)); - thr->signal_ctx = ctx; - } - return ctx; -} - -ScopedInterceptor::ScopedInterceptor(ThreadState *thr, const char *fname, - uptr pc) - : thr_(thr), pc_(pc), in_ignored_lib_(false), ignoring_(false) { - Initialize(thr); - if (!thr_->is_inited) return; - if (!thr_->ignore_interceptors) FuncEntry(thr, pc); - DPrintf("#%d: intercept %s()\n", thr_->tid, fname); - ignoring_ = - !thr_->in_ignored_lib && libignore()->IsIgnored(pc, &in_ignored_lib_); - EnableIgnores(); -} - -ScopedInterceptor::~ScopedInterceptor() { - if (!thr_->is_inited) return; - DisableIgnores(); - if (!thr_->ignore_interceptors) { - ProcessPendingSignals(thr_); - FuncExit(thr_); - CheckNoLocks(thr_); - } -} - -void ScopedInterceptor::EnableIgnores() { - if (ignoring_) { - ThreadIgnoreBegin(thr_, pc_, /*save_stack=*/false); - if (flags()->ignore_noninstrumented_modules) thr_->suppress_reports++; - if (in_ignored_lib_) { - DCHECK(!thr_->in_ignored_lib); - thr_->in_ignored_lib = true; - } - } -} - -void ScopedInterceptor::DisableIgnores() { - if (ignoring_) { - ThreadIgnoreEnd(thr_, pc_); - if (flags()->ignore_noninstrumented_modules) thr_->suppress_reports--; - if (in_ignored_lib_) { - DCHECK(thr_->in_ignored_lib); - thr_->in_ignored_lib = false; - } - } -} - -#define TSAN_INTERCEPT(func) INTERCEPT_FUNCTION(func) -#if SANITIZER_FREEBSD -# define TSAN_INTERCEPT_VER(func, ver) INTERCEPT_FUNCTION(func) -# define TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(func) -# define TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS_THR(func) -#elif SANITIZER_NETBSD -# define TSAN_INTERCEPT_VER(func, ver) INTERCEPT_FUNCTION(func) -# define TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(func) \ - INTERCEPT_FUNCTION(__libc_##func) -# define TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS_THR(func) \ - INTERCEPT_FUNCTION(__libc_thr_##func) -#else -# define TSAN_INTERCEPT_VER(func, ver) INTERCEPT_FUNCTION_VER(func, ver) -# define TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(func) -# define TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS_THR(func) -#endif - -#define READ_STRING_OF_LEN(thr, pc, s, len, n) \ - MemoryAccessRange((thr), (pc), (uptr)(s), \ - common_flags()->strict_string_checks ? (len) + 1 : (n), false) - -#define READ_STRING(thr, pc, s, n) \ - READ_STRING_OF_LEN((thr), (pc), (s), internal_strlen(s), (n)) - -#define BLOCK_REAL(name) (BlockingCall(thr), REAL(name)) - -struct BlockingCall { - explicit BlockingCall(ThreadState *thr) - : thr(thr) - , ctx(SigCtx(thr)) { - for (;;) { - atomic_store(&ctx->in_blocking_func, 1, memory_order_relaxed); - if (atomic_load(&ctx->have_pending_signals, memory_order_relaxed) == 0) - break; - atomic_store(&ctx->in_blocking_func, 0, memory_order_relaxed); - ProcessPendingSignals(thr); - } - // When we are in a "blocking call", we process signals asynchronously - // (right when they arrive). In this context we do not expect to be - // executing any user/runtime code. The known interceptor sequence when - // this is not true is: pthread_join -> munmap(stack). It's fine - // to ignore munmap in this case -- we handle stack shadow separately. - thr->ignore_interceptors++; - } - - ~BlockingCall() { - thr->ignore_interceptors--; - atomic_store(&ctx->in_blocking_func, 0, memory_order_relaxed); - } - - ThreadState *thr; - ThreadSignalContext *ctx; -}; - -TSAN_INTERCEPTOR(unsigned, sleep, unsigned sec) { - SCOPED_TSAN_INTERCEPTOR(sleep, sec); - unsigned res = BLOCK_REAL(sleep)(sec); - AfterSleep(thr, pc); - return res; -} - -TSAN_INTERCEPTOR(int, usleep, long_t usec) { - SCOPED_TSAN_INTERCEPTOR(usleep, usec); - int res = BLOCK_REAL(usleep)(usec); - AfterSleep(thr, pc); - return res; -} - -TSAN_INTERCEPTOR(int, nanosleep, void *req, void *rem) { - SCOPED_TSAN_INTERCEPTOR(nanosleep, req, rem); - int res = BLOCK_REAL(nanosleep)(req, rem); - AfterSleep(thr, pc); - return res; -} - -TSAN_INTERCEPTOR(int, pause, int fake) { - SCOPED_TSAN_INTERCEPTOR(pause, fake); - return BLOCK_REAL(pause)(fake); -} - -static void at_exit_wrapper() { - AtExitCtx *ctx; - { - // Ensure thread-safety. - BlockingMutexLock l(&interceptor_ctx()->atexit_mu); - - // Pop AtExitCtx from the top of the stack of callback functions - uptr element = interceptor_ctx()->AtExitStack.Size() - 1; - ctx = interceptor_ctx()->AtExitStack[element]; - interceptor_ctx()->AtExitStack.PopBack(); - } - - Acquire(cur_thread(), (uptr)0, (uptr)ctx); - ((void(*)())ctx->f)(); - InternalFree(ctx); -} - -static void cxa_at_exit_wrapper(void *arg) { - Acquire(cur_thread(), 0, (uptr)arg); - AtExitCtx *ctx = (AtExitCtx*)arg; - ((void(*)(void *arg))ctx->f)(ctx->arg); - InternalFree(ctx); -} - -static int setup_at_exit_wrapper(ThreadState *thr, uptr pc, void(*f)(), - void *arg, void *dso); - -#if !SANITIZER_ANDROID -TSAN_INTERCEPTOR(int, atexit, void (*f)()) { - if (in_symbolizer()) - return 0; - // We want to setup the atexit callback even if we are in ignored lib - // or after fork. - SCOPED_INTERCEPTOR_RAW(atexit, f); - return setup_at_exit_wrapper(thr, pc, (void(*)())f, 0, 0); -} -#endif - -TSAN_INTERCEPTOR(int, __cxa_atexit, void (*f)(void *a), void *arg, void *dso) { - if (in_symbolizer()) - return 0; - SCOPED_TSAN_INTERCEPTOR(__cxa_atexit, f, arg, dso); - return setup_at_exit_wrapper(thr, pc, (void(*)())f, arg, dso); -} - -static int setup_at_exit_wrapper(ThreadState *thr, uptr pc, void(*f)(), - void *arg, void *dso) { - AtExitCtx *ctx = (AtExitCtx*)InternalAlloc(sizeof(AtExitCtx)); - ctx->f = f; - ctx->arg = arg; - Release(thr, pc, (uptr)ctx); - // Memory allocation in __cxa_atexit will race with free during exit, - // because we do not see synchronization around atexit callback list. - ThreadIgnoreBegin(thr, pc); - int res; - if (!dso) { - // NetBSD does not preserve the 2nd argument if dso is equal to 0 - // Store ctx in a local stack-like structure - - // Ensure thread-safety. - BlockingMutexLock l(&interceptor_ctx()->atexit_mu); - - res = REAL(__cxa_atexit)((void (*)(void *a))at_exit_wrapper, 0, 0); - // Push AtExitCtx on the top of the stack of callback functions - if (!res) { - interceptor_ctx()->AtExitStack.PushBack(ctx); - } - } else { - res = REAL(__cxa_atexit)(cxa_at_exit_wrapper, ctx, dso); - } - ThreadIgnoreEnd(thr, pc); - return res; -} - -#if !SANITIZER_MAC && !SANITIZER_NETBSD -static void on_exit_wrapper(int status, void *arg) { - ThreadState *thr = cur_thread(); - uptr pc = 0; - Acquire(thr, pc, (uptr)arg); - AtExitCtx *ctx = (AtExitCtx*)arg; - ((void(*)(int status, void *arg))ctx->f)(status, ctx->arg); - InternalFree(ctx); -} - -TSAN_INTERCEPTOR(int, on_exit, void(*f)(int, void*), void *arg) { - if (in_symbolizer()) - return 0; - SCOPED_TSAN_INTERCEPTOR(on_exit, f, arg); - AtExitCtx *ctx = (AtExitCtx*)InternalAlloc(sizeof(AtExitCtx)); - ctx->f = (void(*)())f; - ctx->arg = arg; - Release(thr, pc, (uptr)ctx); - // Memory allocation in __cxa_atexit will race with free during exit, - // because we do not see synchronization around atexit callback list. - ThreadIgnoreBegin(thr, pc); - int res = REAL(on_exit)(on_exit_wrapper, ctx); - ThreadIgnoreEnd(thr, pc); - return res; -} -#define TSAN_MAYBE_INTERCEPT_ON_EXIT TSAN_INTERCEPT(on_exit) -#else -#define TSAN_MAYBE_INTERCEPT_ON_EXIT -#endif - -// Cleanup old bufs. -static void JmpBufGarbageCollect(ThreadState *thr, uptr sp) { - for (uptr i = 0; i < thr->jmp_bufs.Size(); i++) { - JmpBuf *buf = &thr->jmp_bufs[i]; - if (buf->sp <= sp) { - uptr sz = thr->jmp_bufs.Size(); - internal_memcpy(buf, &thr->jmp_bufs[sz - 1], sizeof(*buf)); - thr->jmp_bufs.PopBack(); - i--; - } - } -} - -static void SetJmp(ThreadState *thr, uptr sp) { - if (!thr->is_inited) // called from libc guts during bootstrap - return; - // Cleanup old bufs. - JmpBufGarbageCollect(thr, sp); - // Remember the buf. - JmpBuf *buf = thr->jmp_bufs.PushBack(); - buf->sp = sp; - buf->shadow_stack_pos = thr->shadow_stack_pos; - ThreadSignalContext *sctx = SigCtx(thr); - buf->int_signal_send = sctx ? sctx->int_signal_send : 0; - buf->in_blocking_func = sctx ? - atomic_load(&sctx->in_blocking_func, memory_order_relaxed) : - false; - buf->in_signal_handler = atomic_load(&thr->in_signal_handler, - memory_order_relaxed); -} - -static void LongJmp(ThreadState *thr, uptr *env) { - uptr sp = ExtractLongJmpSp(env); - // Find the saved buf with matching sp. - for (uptr i = 0; i < thr->jmp_bufs.Size(); i++) { - JmpBuf *buf = &thr->jmp_bufs[i]; - if (buf->sp == sp) { - CHECK_GE(thr->shadow_stack_pos, buf->shadow_stack_pos); - // Unwind the stack. - while (thr->shadow_stack_pos > buf->shadow_stack_pos) - FuncExit(thr); - ThreadSignalContext *sctx = SigCtx(thr); - if (sctx) { - sctx->int_signal_send = buf->int_signal_send; - atomic_store(&sctx->in_blocking_func, buf->in_blocking_func, - memory_order_relaxed); - } - atomic_store(&thr->in_signal_handler, buf->in_signal_handler, - memory_order_relaxed); - JmpBufGarbageCollect(thr, buf->sp - 1); // do not collect buf->sp - return; - } - } - Printf("ThreadSanitizer: can't find longjmp buf\n"); - CHECK(0); -} - -// FIXME: put everything below into a common extern "C" block? -extern "C" void __tsan_setjmp(uptr sp) { - cur_thread_init(); - SetJmp(cur_thread(), sp); -} - -#if SANITIZER_MAC -TSAN_INTERCEPTOR(int, setjmp, void *env); -TSAN_INTERCEPTOR(int, _setjmp, void *env); -TSAN_INTERCEPTOR(int, sigsetjmp, void *env); -#else // SANITIZER_MAC - -#if SANITIZER_NETBSD -#define setjmp_symname __setjmp14 -#define sigsetjmp_symname __sigsetjmp14 -#else -#define setjmp_symname setjmp -#define sigsetjmp_symname sigsetjmp -#endif - -#define TSAN_INTERCEPTOR_SETJMP_(x) __interceptor_ ## x -#define TSAN_INTERCEPTOR_SETJMP__(x) TSAN_INTERCEPTOR_SETJMP_(x) -#define TSAN_INTERCEPTOR_SETJMP TSAN_INTERCEPTOR_SETJMP__(setjmp_symname) -#define TSAN_INTERCEPTOR_SIGSETJMP TSAN_INTERCEPTOR_SETJMP__(sigsetjmp_symname) - -#define TSAN_STRING_SETJMP SANITIZER_STRINGIFY(setjmp_symname) -#define TSAN_STRING_SIGSETJMP SANITIZER_STRINGIFY(sigsetjmp_symname) - -// Not called. Merely to satisfy TSAN_INTERCEPT(). -extern "C" SANITIZER_INTERFACE_ATTRIBUTE -int TSAN_INTERCEPTOR_SETJMP(void *env); -extern "C" int TSAN_INTERCEPTOR_SETJMP(void *env) { - CHECK(0); - return 0; -} - -// FIXME: any reason to have a separate declaration? -extern "C" SANITIZER_INTERFACE_ATTRIBUTE -int __interceptor__setjmp(void *env); -extern "C" int __interceptor__setjmp(void *env) { - CHECK(0); - return 0; -} - -extern "C" SANITIZER_INTERFACE_ATTRIBUTE -int TSAN_INTERCEPTOR_SIGSETJMP(void *env); -extern "C" int TSAN_INTERCEPTOR_SIGSETJMP(void *env) { - CHECK(0); - return 0; -} - -#if !SANITIZER_NETBSD -extern "C" SANITIZER_INTERFACE_ATTRIBUTE -int __interceptor___sigsetjmp(void *env); -extern "C" int __interceptor___sigsetjmp(void *env) { - CHECK(0); - return 0; -} -#endif - -extern "C" int setjmp_symname(void *env); -extern "C" int _setjmp(void *env); -extern "C" int sigsetjmp_symname(void *env); -#if !SANITIZER_NETBSD -extern "C" int __sigsetjmp(void *env); -#endif -DEFINE_REAL(int, setjmp_symname, void *env) -DEFINE_REAL(int, _setjmp, void *env) -DEFINE_REAL(int, sigsetjmp_symname, void *env) -#if !SANITIZER_NETBSD -DEFINE_REAL(int, __sigsetjmp, void *env) -#endif -#endif // SANITIZER_MAC - -#if SANITIZER_NETBSD -#define longjmp_symname __longjmp14 -#define siglongjmp_symname __siglongjmp14 -#else -#define longjmp_symname longjmp -#define siglongjmp_symname siglongjmp -#endif - -TSAN_INTERCEPTOR(void, longjmp_symname, uptr *env, int val) { - // Note: if we call REAL(longjmp) in the context of ScopedInterceptor, - // bad things will happen. We will jump over ScopedInterceptor dtor and can - // leave thr->in_ignored_lib set. - { - SCOPED_INTERCEPTOR_RAW(longjmp_symname, env, val); - } - LongJmp(cur_thread(), env); - REAL(longjmp_symname)(env, val); -} - -TSAN_INTERCEPTOR(void, siglongjmp_symname, uptr *env, int val) { - { - SCOPED_INTERCEPTOR_RAW(siglongjmp_symname, env, val); - } - LongJmp(cur_thread(), env); - REAL(siglongjmp_symname)(env, val); -} - -#if SANITIZER_NETBSD -TSAN_INTERCEPTOR(void, _longjmp, uptr *env, int val) { - { - SCOPED_INTERCEPTOR_RAW(_longjmp, env, val); - } - LongJmp(cur_thread(), env); - REAL(_longjmp)(env, val); -} -#endif - -#if !SANITIZER_MAC -TSAN_INTERCEPTOR(void*, malloc, uptr size) { - if (in_symbolizer()) - return InternalAlloc(size); - void *p = 0; - { - SCOPED_INTERCEPTOR_RAW(malloc, size); - p = user_alloc(thr, pc, size); - } - invoke_malloc_hook(p, size); - return p; -} - -TSAN_INTERCEPTOR(void*, __libc_memalign, uptr align, uptr sz) { - SCOPED_TSAN_INTERCEPTOR(__libc_memalign, align, sz); - return user_memalign(thr, pc, align, sz); -} - -TSAN_INTERCEPTOR(void*, calloc, uptr size, uptr n) { - if (in_symbolizer()) - return InternalCalloc(size, n); - void *p = 0; - { - SCOPED_INTERCEPTOR_RAW(calloc, size, n); - p = user_calloc(thr, pc, size, n); - } - invoke_malloc_hook(p, n * size); - return p; -} - -TSAN_INTERCEPTOR(void*, realloc, void *p, uptr size) { - if (in_symbolizer()) - return InternalRealloc(p, size); - if (p) - invoke_free_hook(p); - { - SCOPED_INTERCEPTOR_RAW(realloc, p, size); - p = user_realloc(thr, pc, p, size); - } - invoke_malloc_hook(p, size); - return p; -} - -TSAN_INTERCEPTOR(void*, reallocarray, void *p, uptr size, uptr n) { - if (in_symbolizer()) - return InternalReallocArray(p, size, n); - if (p) - invoke_free_hook(p); - { - SCOPED_INTERCEPTOR_RAW(reallocarray, p, size, n); - p = user_reallocarray(thr, pc, p, size, n); - } - invoke_malloc_hook(p, size); - return p; -} - -TSAN_INTERCEPTOR(void, free, void *p) { - if (p == 0) - return; - if (in_symbolizer()) - return InternalFree(p); - invoke_free_hook(p); - SCOPED_INTERCEPTOR_RAW(free, p); - user_free(thr, pc, p); -} - -TSAN_INTERCEPTOR(void, cfree, void *p) { - if (p == 0) - return; - if (in_symbolizer()) - return InternalFree(p); - invoke_free_hook(p); - SCOPED_INTERCEPTOR_RAW(cfree, p); - user_free(thr, pc, p); -} - -TSAN_INTERCEPTOR(uptr, malloc_usable_size, void *p) { - SCOPED_INTERCEPTOR_RAW(malloc_usable_size, p); - return user_alloc_usable_size(p); -} -#endif - -TSAN_INTERCEPTOR(char*, strcpy, char *dst, const char *src) { // NOLINT - SCOPED_TSAN_INTERCEPTOR(strcpy, dst, src); // NOLINT - uptr srclen = internal_strlen(src); - MemoryAccessRange(thr, pc, (uptr)dst, srclen + 1, true); - MemoryAccessRange(thr, pc, (uptr)src, srclen + 1, false); - return REAL(strcpy)(dst, src); // NOLINT -} - -TSAN_INTERCEPTOR(char*, strncpy, char *dst, char *src, uptr n) { - SCOPED_TSAN_INTERCEPTOR(strncpy, dst, src, n); - uptr srclen = internal_strnlen(src, n); - MemoryAccessRange(thr, pc, (uptr)dst, n, true); - MemoryAccessRange(thr, pc, (uptr)src, min(srclen + 1, n), false); - return REAL(strncpy)(dst, src, n); -} - -TSAN_INTERCEPTOR(char*, strdup, const char *str) { - SCOPED_TSAN_INTERCEPTOR(strdup, str); - // strdup will call malloc, so no instrumentation is required here. - return REAL(strdup)(str); -} - -static bool fix_mmap_addr(void **addr, long_t sz, int flags) { - if (*addr) { - if (!IsAppMem((uptr)*addr) || !IsAppMem((uptr)*addr + sz - 1)) { - if (flags & MAP_FIXED) { - errno = errno_EINVAL; - return false; - } else { - *addr = 0; - } - } - } - return true; -} - -template -static void *mmap_interceptor(ThreadState *thr, uptr pc, Mmap real_mmap, - void *addr, SIZE_T sz, int prot, int flags, - int fd, OFF64_T off) { - if (!fix_mmap_addr(&addr, sz, flags)) return MAP_FAILED; - void *res = real_mmap(addr, sz, prot, flags, fd, off); - if (res != MAP_FAILED) { - if (fd > 0) FdAccess(thr, pc, fd); - if (thr->ignore_reads_and_writes == 0) - MemoryRangeImitateWrite(thr, pc, (uptr)res, sz); - else - MemoryResetRange(thr, pc, (uptr)res, sz); - } - return res; -} - -TSAN_INTERCEPTOR(int, munmap, void *addr, long_t sz) { - SCOPED_TSAN_INTERCEPTOR(munmap, addr, sz); - if (sz != 0) { - // If sz == 0, munmap will return EINVAL and don't unmap any memory. - DontNeedShadowFor((uptr)addr, sz); - ScopedGlobalProcessor sgp; - ctx->metamap.ResetRange(thr->proc(), (uptr)addr, (uptr)sz); - } - int res = REAL(munmap)(addr, sz); - return res; -} - -#if SANITIZER_LINUX -TSAN_INTERCEPTOR(void*, memalign, uptr align, uptr sz) { - SCOPED_INTERCEPTOR_RAW(memalign, align, sz); - return user_memalign(thr, pc, align, sz); -} -#define TSAN_MAYBE_INTERCEPT_MEMALIGN TSAN_INTERCEPT(memalign) -#else -#define TSAN_MAYBE_INTERCEPT_MEMALIGN -#endif - -#if !SANITIZER_MAC -TSAN_INTERCEPTOR(void*, aligned_alloc, uptr align, uptr sz) { - if (in_symbolizer()) - return InternalAlloc(sz, nullptr, align); - SCOPED_INTERCEPTOR_RAW(aligned_alloc, align, sz); - return user_aligned_alloc(thr, pc, align, sz); -} - -TSAN_INTERCEPTOR(void*, valloc, uptr sz) { - if (in_symbolizer()) - return InternalAlloc(sz, nullptr, GetPageSizeCached()); - SCOPED_INTERCEPTOR_RAW(valloc, sz); - return user_valloc(thr, pc, sz); -} -#endif - -#if SANITIZER_LINUX -TSAN_INTERCEPTOR(void*, pvalloc, uptr sz) { - if (in_symbolizer()) { - uptr PageSize = GetPageSizeCached(); - sz = sz ? RoundUpTo(sz, PageSize) : PageSize; - return InternalAlloc(sz, nullptr, PageSize); - } - SCOPED_INTERCEPTOR_RAW(pvalloc, sz); - return user_pvalloc(thr, pc, sz); -} -#define TSAN_MAYBE_INTERCEPT_PVALLOC TSAN_INTERCEPT(pvalloc) -#else -#define TSAN_MAYBE_INTERCEPT_PVALLOC -#endif - -#if !SANITIZER_MAC -TSAN_INTERCEPTOR(int, posix_memalign, void **memptr, uptr align, uptr sz) { - if (in_symbolizer()) { - void *p = InternalAlloc(sz, nullptr, align); - if (!p) - return errno_ENOMEM; - *memptr = p; - return 0; - } - SCOPED_INTERCEPTOR_RAW(posix_memalign, memptr, align, sz); - return user_posix_memalign(thr, pc, memptr, align, sz); -} -#endif - -// __cxa_guard_acquire and friends need to be intercepted in a special way - -// regular interceptors will break statically-linked libstdc++. Linux -// interceptors are especially defined as weak functions (so that they don't -// cause link errors when user defines them as well). So they silently -// auto-disable themselves when such symbol is already present in the binary. If -// we link libstdc++ statically, it will bring own __cxa_guard_acquire which -// will silently replace our interceptor. That's why on Linux we simply export -// these interceptors with INTERFACE_ATTRIBUTE. -// On OS X, we don't support statically linking, so we just use a regular -// interceptor. -#if SANITIZER_MAC -#define STDCXX_INTERCEPTOR TSAN_INTERCEPTOR -#else -#define STDCXX_INTERCEPTOR(rettype, name, ...) \ - extern "C" rettype INTERFACE_ATTRIBUTE name(__VA_ARGS__) -#endif - -// Used in thread-safe function static initialization. -STDCXX_INTERCEPTOR(int, __cxa_guard_acquire, atomic_uint32_t *g) { - SCOPED_INTERCEPTOR_RAW(__cxa_guard_acquire, g); - OnPotentiallyBlockingRegionBegin(); - auto on_exit = at_scope_exit(&OnPotentiallyBlockingRegionEnd); - for (;;) { - u32 cmp = atomic_load(g, memory_order_acquire); - if (cmp == 0) { - if (atomic_compare_exchange_strong(g, &cmp, 1<<16, memory_order_relaxed)) - return 1; - } else if (cmp == 1) { - Acquire(thr, pc, (uptr)g); - return 0; - } else { - internal_sched_yield(); - } - } -} - -STDCXX_INTERCEPTOR(void, __cxa_guard_release, atomic_uint32_t *g) { - SCOPED_INTERCEPTOR_RAW(__cxa_guard_release, g); - Release(thr, pc, (uptr)g); - atomic_store(g, 1, memory_order_release); -} - -STDCXX_INTERCEPTOR(void, __cxa_guard_abort, atomic_uint32_t *g) { - SCOPED_INTERCEPTOR_RAW(__cxa_guard_abort, g); - atomic_store(g, 0, memory_order_relaxed); -} - -namespace __tsan { -void DestroyThreadState() { - ThreadState *thr = cur_thread(); - Processor *proc = thr->proc(); - ThreadFinish(thr); - ProcUnwire(proc, thr); - ProcDestroy(proc); - ThreadSignalContext *sctx = thr->signal_ctx; - if (sctx) { - thr->signal_ctx = 0; - UnmapOrDie(sctx, sizeof(*sctx)); - } - DTLS_Destroy(); - cur_thread_finalize(); -} -} // namespace __tsan - -#if !SANITIZER_MAC && !SANITIZER_NETBSD && !SANITIZER_FREEBSD -static void thread_finalize(void *v) { - uptr iter = (uptr)v; - if (iter > 1) { - if (pthread_setspecific(interceptor_ctx()->finalize_key, - (void*)(iter - 1))) { - Printf("ThreadSanitizer: failed to set thread key\n"); - Die(); - } - return; - } - DestroyThreadState(); -} -#endif - - -struct ThreadParam { - void* (*callback)(void *arg); - void *param; - atomic_uintptr_t tid; -}; - -extern "C" void *__tsan_thread_start_func(void *arg) { - ThreadParam *p = (ThreadParam*)arg; - void* (*callback)(void *arg) = p->callback; - void *param = p->param; - int tid = 0; - { - cur_thread_init(); - ThreadState *thr = cur_thread(); - // Thread-local state is not initialized yet. - ScopedIgnoreInterceptors ignore; -#if !SANITIZER_MAC && !SANITIZER_NETBSD && !SANITIZER_FREEBSD - ThreadIgnoreBegin(thr, 0); - if (pthread_setspecific(interceptor_ctx()->finalize_key, - (void *)GetPthreadDestructorIterations())) { - Printf("ThreadSanitizer: failed to set thread key\n"); - Die(); - } - ThreadIgnoreEnd(thr, 0); -#endif - while ((tid = atomic_load(&p->tid, memory_order_acquire)) == 0) - internal_sched_yield(); - Processor *proc = ProcCreate(); - ProcWire(proc, thr); - ThreadStart(thr, tid, GetTid(), ThreadType::Regular); - atomic_store(&p->tid, 0, memory_order_release); - } - void *res = callback(param); - // Prevent the callback from being tail called, - // it mixes up stack traces. - volatile int foo = 42; - foo++; - return res; -} - -TSAN_INTERCEPTOR(int, pthread_create, - void *th, void *attr, void *(*callback)(void*), void * param) { - SCOPED_INTERCEPTOR_RAW(pthread_create, th, attr, callback, param); - - MaybeSpawnBackgroundThread(); - - if (ctx->after_multithreaded_fork) { - if (flags()->die_after_fork) { - Report("ThreadSanitizer: starting new threads after multi-threaded " - "fork is not supported. Dying (set die_after_fork=0 to override)\n"); - Die(); - } else { - VPrintf(1, "ThreadSanitizer: starting new threads after multi-threaded " - "fork is not supported (pid %d). Continuing because of " - "die_after_fork=0, but you are on your own\n", internal_getpid()); - } - } - __sanitizer_pthread_attr_t myattr; - if (attr == 0) { - pthread_attr_init(&myattr); - attr = &myattr; - } - int detached = 0; - REAL(pthread_attr_getdetachstate)(attr, &detached); - AdjustStackSize(attr); - - ThreadParam p; - p.callback = callback; - p.param = param; - atomic_store(&p.tid, 0, memory_order_relaxed); - int res = -1; - { - // Otherwise we see false positives in pthread stack manipulation. - ScopedIgnoreInterceptors ignore; - ThreadIgnoreBegin(thr, pc); - res = REAL(pthread_create)(th, attr, __tsan_thread_start_func, &p); - ThreadIgnoreEnd(thr, pc); - } - if (res == 0) { - int tid = ThreadCreate(thr, pc, *(uptr*)th, IsStateDetached(detached)); - CHECK_NE(tid, 0); - // Synchronization on p.tid serves two purposes: - // 1. ThreadCreate must finish before the new thread starts. - // Otherwise the new thread can call pthread_detach, but the pthread_t - // identifier is not yet registered in ThreadRegistry by ThreadCreate. - // 2. ThreadStart must finish before this thread continues. - // Otherwise, this thread can call pthread_detach and reset thr->sync - // before the new thread got a chance to acquire from it in ThreadStart. - atomic_store(&p.tid, tid, memory_order_release); - while (atomic_load(&p.tid, memory_order_acquire) != 0) - internal_sched_yield(); - } - if (attr == &myattr) - pthread_attr_destroy(&myattr); - return res; -} - -TSAN_INTERCEPTOR(int, pthread_join, void *th, void **ret) { - SCOPED_INTERCEPTOR_RAW(pthread_join, th, ret); - int tid = ThreadTid(thr, pc, (uptr)th); - ThreadIgnoreBegin(thr, pc); - int res = BLOCK_REAL(pthread_join)(th, ret); - ThreadIgnoreEnd(thr, pc); - if (res == 0) { - ThreadJoin(thr, pc, tid); - } - return res; -} - -DEFINE_REAL_PTHREAD_FUNCTIONS - -TSAN_INTERCEPTOR(int, pthread_detach, void *th) { - SCOPED_TSAN_INTERCEPTOR(pthread_detach, th); - int tid = ThreadTid(thr, pc, (uptr)th); - int res = REAL(pthread_detach)(th); - if (res == 0) { - ThreadDetach(thr, pc, tid); - } - return res; -} - -TSAN_INTERCEPTOR(void, pthread_exit, void *retval) { - { - SCOPED_INTERCEPTOR_RAW(pthread_exit, retval); -#if !SANITIZER_MAC && !SANITIZER_ANDROID - CHECK_EQ(thr, &cur_thread_placeholder); -#endif - } - REAL(pthread_exit)(retval); -} - -#if SANITIZER_LINUX -TSAN_INTERCEPTOR(int, pthread_tryjoin_np, void *th, void **ret) { - SCOPED_TSAN_INTERCEPTOR(pthread_tryjoin_np, th, ret); - int tid = ThreadTid(thr, pc, (uptr)th); - ThreadIgnoreBegin(thr, pc); - int res = REAL(pthread_tryjoin_np)(th, ret); - ThreadIgnoreEnd(thr, pc); - if (res == 0) - ThreadJoin(thr, pc, tid); - else - ThreadNotJoined(thr, pc, tid, (uptr)th); - return res; -} - -TSAN_INTERCEPTOR(int, pthread_timedjoin_np, void *th, void **ret, - const struct timespec *abstime) { - SCOPED_TSAN_INTERCEPTOR(pthread_timedjoin_np, th, ret, abstime); - int tid = ThreadTid(thr, pc, (uptr)th); - ThreadIgnoreBegin(thr, pc); - int res = BLOCK_REAL(pthread_timedjoin_np)(th, ret, abstime); - ThreadIgnoreEnd(thr, pc); - if (res == 0) - ThreadJoin(thr, pc, tid); - else - ThreadNotJoined(thr, pc, tid, (uptr)th); - return res; -} -#endif - -// Problem: -// NPTL implementation of pthread_cond has 2 versions (2.2.5 and 2.3.2). -// pthread_cond_t has different size in the different versions. -// If call new REAL functions for old pthread_cond_t, they will corrupt memory -// after pthread_cond_t (old cond is smaller). -// If we call old REAL functions for new pthread_cond_t, we will lose some -// functionality (e.g. old functions do not support waiting against -// CLOCK_REALTIME). -// Proper handling would require to have 2 versions of interceptors as well. -// But this is messy, in particular requires linker scripts when sanitizer -// runtime is linked into a shared library. -// Instead we assume we don't have dynamic libraries built against old -// pthread (2.2.5 is dated by 2002). And provide legacy_pthread_cond flag -// that allows to work with old libraries (but this mode does not support -// some features, e.g. pthread_condattr_getpshared). -static void *init_cond(void *c, bool force = false) { - // sizeof(pthread_cond_t) >= sizeof(uptr) in both versions. - // So we allocate additional memory on the side large enough to hold - // any pthread_cond_t object. Always call new REAL functions, but pass - // the aux object to them. - // Note: the code assumes that PTHREAD_COND_INITIALIZER initializes - // first word of pthread_cond_t to zero. - // It's all relevant only for linux. - if (!common_flags()->legacy_pthread_cond) - return c; - atomic_uintptr_t *p = (atomic_uintptr_t*)c; - uptr cond = atomic_load(p, memory_order_acquire); - if (!force && cond != 0) - return (void*)cond; - void *newcond = WRAP(malloc)(pthread_cond_t_sz); - internal_memset(newcond, 0, pthread_cond_t_sz); - if (atomic_compare_exchange_strong(p, &cond, (uptr)newcond, - memory_order_acq_rel)) - return newcond; - WRAP(free)(newcond); - return (void*)cond; -} - -struct CondMutexUnlockCtx { - ScopedInterceptor *si; - ThreadState *thr; - uptr pc; - void *m; -}; - -static void cond_mutex_unlock(CondMutexUnlockCtx *arg) { - // pthread_cond_wait interceptor has enabled async signal delivery - // (see BlockingCall below). Disable async signals since we are running - // tsan code. Also ScopedInterceptor and BlockingCall destructors won't run - // since the thread is cancelled, so we have to manually execute them - // (the thread still can run some user code due to pthread_cleanup_push). - ThreadSignalContext *ctx = SigCtx(arg->thr); - CHECK_EQ(atomic_load(&ctx->in_blocking_func, memory_order_relaxed), 1); - atomic_store(&ctx->in_blocking_func, 0, memory_order_relaxed); - MutexPostLock(arg->thr, arg->pc, (uptr)arg->m, MutexFlagDoPreLockOnPostLock); - // Undo BlockingCall ctor effects. - arg->thr->ignore_interceptors--; - arg->si->~ScopedInterceptor(); -} - -INTERCEPTOR(int, pthread_cond_init, void *c, void *a) { - void *cond = init_cond(c, true); - SCOPED_TSAN_INTERCEPTOR(pthread_cond_init, cond, a); - MemoryAccessRange(thr, pc, (uptr)c, sizeof(uptr), true); - return REAL(pthread_cond_init)(cond, a); -} - -static int cond_wait(ThreadState *thr, uptr pc, ScopedInterceptor *si, - int (*fn)(void *c, void *m, void *abstime), void *c, - void *m, void *t) { - MemoryAccessRange(thr, pc, (uptr)c, sizeof(uptr), false); - MutexUnlock(thr, pc, (uptr)m); - CondMutexUnlockCtx arg = {si, thr, pc, m}; - int res = 0; - // This ensures that we handle mutex lock even in case of pthread_cancel. - // See test/tsan/cond_cancel.cpp. - { - // Enable signal delivery while the thread is blocked. - BlockingCall bc(thr); - res = call_pthread_cancel_with_cleanup( - fn, c, m, t, (void (*)(void *arg))cond_mutex_unlock, &arg); - } - if (res == errno_EOWNERDEAD) MutexRepair(thr, pc, (uptr)m); - MutexPostLock(thr, pc, (uptr)m, MutexFlagDoPreLockOnPostLock); - return res; -} - -INTERCEPTOR(int, pthread_cond_wait, void *c, void *m) { - void *cond = init_cond(c); - SCOPED_TSAN_INTERCEPTOR(pthread_cond_wait, cond, m); - return cond_wait(thr, pc, &si, (int (*)(void *c, void *m, void *abstime))REAL( - pthread_cond_wait), - cond, m, 0); -} - -INTERCEPTOR(int, pthread_cond_timedwait, void *c, void *m, void *abstime) { - void *cond = init_cond(c); - SCOPED_TSAN_INTERCEPTOR(pthread_cond_timedwait, cond, m, abstime); - return cond_wait(thr, pc, &si, REAL(pthread_cond_timedwait), cond, m, - abstime); -} - -#if SANITIZER_MAC -INTERCEPTOR(int, pthread_cond_timedwait_relative_np, void *c, void *m, - void *reltime) { - void *cond = init_cond(c); - SCOPED_TSAN_INTERCEPTOR(pthread_cond_timedwait_relative_np, cond, m, reltime); - return cond_wait(thr, pc, &si, REAL(pthread_cond_timedwait_relative_np), cond, - m, reltime); -} -#endif - -INTERCEPTOR(int, pthread_cond_signal, void *c) { - void *cond = init_cond(c); - SCOPED_TSAN_INTERCEPTOR(pthread_cond_signal, cond); - MemoryAccessRange(thr, pc, (uptr)c, sizeof(uptr), false); - return REAL(pthread_cond_signal)(cond); -} - -INTERCEPTOR(int, pthread_cond_broadcast, void *c) { - void *cond = init_cond(c); - SCOPED_TSAN_INTERCEPTOR(pthread_cond_broadcast, cond); - MemoryAccessRange(thr, pc, (uptr)c, sizeof(uptr), false); - return REAL(pthread_cond_broadcast)(cond); -} - -INTERCEPTOR(int, pthread_cond_destroy, void *c) { - void *cond = init_cond(c); - SCOPED_TSAN_INTERCEPTOR(pthread_cond_destroy, cond); - MemoryAccessRange(thr, pc, (uptr)c, sizeof(uptr), true); - int res = REAL(pthread_cond_destroy)(cond); - if (common_flags()->legacy_pthread_cond) { - // Free our aux cond and zero the pointer to not leave dangling pointers. - WRAP(free)(cond); - atomic_store((atomic_uintptr_t*)c, 0, memory_order_relaxed); - } - return res; -} - -TSAN_INTERCEPTOR(int, pthread_mutex_init, void *m, void *a) { - SCOPED_TSAN_INTERCEPTOR(pthread_mutex_init, m, a); - int res = REAL(pthread_mutex_init)(m, a); - if (res == 0) { - u32 flagz = 0; - if (a) { - int type = 0; - if (REAL(pthread_mutexattr_gettype)(a, &type) == 0) - if (type == PTHREAD_MUTEX_RECURSIVE || - type == PTHREAD_MUTEX_RECURSIVE_NP) - flagz |= MutexFlagWriteReentrant; - } - MutexCreate(thr, pc, (uptr)m, flagz); - } - return res; -} - -TSAN_INTERCEPTOR(int, pthread_mutex_destroy, void *m) { - SCOPED_TSAN_INTERCEPTOR(pthread_mutex_destroy, m); - int res = REAL(pthread_mutex_destroy)(m); - if (res == 0 || res == errno_EBUSY) { - MutexDestroy(thr, pc, (uptr)m); - } - return res; -} - -TSAN_INTERCEPTOR(int, pthread_mutex_trylock, void *m) { - SCOPED_TSAN_INTERCEPTOR(pthread_mutex_trylock, m); - int res = REAL(pthread_mutex_trylock)(m); - if (res == errno_EOWNERDEAD) - MutexRepair(thr, pc, (uptr)m); - if (res == 0 || res == errno_EOWNERDEAD) - MutexPostLock(thr, pc, (uptr)m, MutexFlagTryLock); - return res; -} - -#if !SANITIZER_MAC -TSAN_INTERCEPTOR(int, pthread_mutex_timedlock, void *m, void *abstime) { - SCOPED_TSAN_INTERCEPTOR(pthread_mutex_timedlock, m, abstime); - int res = REAL(pthread_mutex_timedlock)(m, abstime); - if (res == 0) { - MutexPostLock(thr, pc, (uptr)m, MutexFlagTryLock); - } - return res; -} -#endif - -#if !SANITIZER_MAC -TSAN_INTERCEPTOR(int, pthread_spin_init, void *m, int pshared) { - SCOPED_TSAN_INTERCEPTOR(pthread_spin_init, m, pshared); - int res = REAL(pthread_spin_init)(m, pshared); - if (res == 0) { - MutexCreate(thr, pc, (uptr)m); - } - return res; -} - -TSAN_INTERCEPTOR(int, pthread_spin_destroy, void *m) { - SCOPED_TSAN_INTERCEPTOR(pthread_spin_destroy, m); - int res = REAL(pthread_spin_destroy)(m); - if (res == 0) { - MutexDestroy(thr, pc, (uptr)m); - } - return res; -} - -TSAN_INTERCEPTOR(int, pthread_spin_lock, void *m) { - SCOPED_TSAN_INTERCEPTOR(pthread_spin_lock, m); - MutexPreLock(thr, pc, (uptr)m); - int res = REAL(pthread_spin_lock)(m); - if (res == 0) { - MutexPostLock(thr, pc, (uptr)m); - } - return res; -} - -TSAN_INTERCEPTOR(int, pthread_spin_trylock, void *m) { - SCOPED_TSAN_INTERCEPTOR(pthread_spin_trylock, m); - int res = REAL(pthread_spin_trylock)(m); - if (res == 0) { - MutexPostLock(thr, pc, (uptr)m, MutexFlagTryLock); - } - return res; -} - -TSAN_INTERCEPTOR(int, pthread_spin_unlock, void *m) { - SCOPED_TSAN_INTERCEPTOR(pthread_spin_unlock, m); - MutexUnlock(thr, pc, (uptr)m); - int res = REAL(pthread_spin_unlock)(m); - return res; -} -#endif - -TSAN_INTERCEPTOR(int, pthread_rwlock_init, void *m, void *a) { - SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_init, m, a); - int res = REAL(pthread_rwlock_init)(m, a); - if (res == 0) { - MutexCreate(thr, pc, (uptr)m); - } - return res; -} - -TSAN_INTERCEPTOR(int, pthread_rwlock_destroy, void *m) { - SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_destroy, m); - int res = REAL(pthread_rwlock_destroy)(m); - if (res == 0) { - MutexDestroy(thr, pc, (uptr)m); - } - return res; -} - -TSAN_INTERCEPTOR(int, pthread_rwlock_rdlock, void *m) { - SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_rdlock, m); - MutexPreReadLock(thr, pc, (uptr)m); - int res = REAL(pthread_rwlock_rdlock)(m); - if (res == 0) { - MutexPostReadLock(thr, pc, (uptr)m); - } - return res; -} - -TSAN_INTERCEPTOR(int, pthread_rwlock_tryrdlock, void *m) { - SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_tryrdlock, m); - int res = REAL(pthread_rwlock_tryrdlock)(m); - if (res == 0) { - MutexPostReadLock(thr, pc, (uptr)m, MutexFlagTryLock); - } - return res; -} - -#if !SANITIZER_MAC -TSAN_INTERCEPTOR(int, pthread_rwlock_timedrdlock, void *m, void *abstime) { - SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_timedrdlock, m, abstime); - int res = REAL(pthread_rwlock_timedrdlock)(m, abstime); - if (res == 0) { - MutexPostReadLock(thr, pc, (uptr)m); - } - return res; -} -#endif - -TSAN_INTERCEPTOR(int, pthread_rwlock_wrlock, void *m) { - SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_wrlock, m); - MutexPreLock(thr, pc, (uptr)m); - int res = REAL(pthread_rwlock_wrlock)(m); - if (res == 0) { - MutexPostLock(thr, pc, (uptr)m); - } - return res; -} - -TSAN_INTERCEPTOR(int, pthread_rwlock_trywrlock, void *m) { - SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_trywrlock, m); - int res = REAL(pthread_rwlock_trywrlock)(m); - if (res == 0) { - MutexPostLock(thr, pc, (uptr)m, MutexFlagTryLock); - } - return res; -} - -#if !SANITIZER_MAC -TSAN_INTERCEPTOR(int, pthread_rwlock_timedwrlock, void *m, void *abstime) { - SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_timedwrlock, m, abstime); - int res = REAL(pthread_rwlock_timedwrlock)(m, abstime); - if (res == 0) { - MutexPostLock(thr, pc, (uptr)m, MutexFlagTryLock); - } - return res; -} -#endif - -TSAN_INTERCEPTOR(int, pthread_rwlock_unlock, void *m) { - SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_unlock, m); - MutexReadOrWriteUnlock(thr, pc, (uptr)m); - int res = REAL(pthread_rwlock_unlock)(m); - return res; -} - -#if !SANITIZER_MAC -TSAN_INTERCEPTOR(int, pthread_barrier_init, void *b, void *a, unsigned count) { - SCOPED_TSAN_INTERCEPTOR(pthread_barrier_init, b, a, count); - MemoryWrite(thr, pc, (uptr)b, kSizeLog1); - int res = REAL(pthread_barrier_init)(b, a, count); - return res; -} - -TSAN_INTERCEPTOR(int, pthread_barrier_destroy, void *b) { - SCOPED_TSAN_INTERCEPTOR(pthread_barrier_destroy, b); - MemoryWrite(thr, pc, (uptr)b, kSizeLog1); - int res = REAL(pthread_barrier_destroy)(b); - return res; -} - -TSAN_INTERCEPTOR(int, pthread_barrier_wait, void *b) { - SCOPED_TSAN_INTERCEPTOR(pthread_barrier_wait, b); - Release(thr, pc, (uptr)b); - MemoryRead(thr, pc, (uptr)b, kSizeLog1); - int res = REAL(pthread_barrier_wait)(b); - MemoryRead(thr, pc, (uptr)b, kSizeLog1); - if (res == 0 || res == PTHREAD_BARRIER_SERIAL_THREAD) { - Acquire(thr, pc, (uptr)b); - } - return res; -} -#endif - -TSAN_INTERCEPTOR(int, pthread_once, void *o, void (*f)()) { - SCOPED_INTERCEPTOR_RAW(pthread_once, o, f); - if (o == 0 || f == 0) - return errno_EINVAL; - atomic_uint32_t *a; - - if (SANITIZER_MAC) - a = static_cast((void *)((char *)o + sizeof(long_t))); - else if (SANITIZER_NETBSD) - a = static_cast - ((void *)((char *)o + __sanitizer::pthread_mutex_t_sz)); - else - a = static_cast(o); - - u32 v = atomic_load(a, memory_order_acquire); - if (v == 0 && atomic_compare_exchange_strong(a, &v, 1, - memory_order_relaxed)) { - (*f)(); - if (!thr->in_ignored_lib) - Release(thr, pc, (uptr)o); - atomic_store(a, 2, memory_order_release); - } else { - while (v != 2) { - internal_sched_yield(); - v = atomic_load(a, memory_order_acquire); - } - if (!thr->in_ignored_lib) - Acquire(thr, pc, (uptr)o); - } - return 0; -} - -#if SANITIZER_LINUX && !SANITIZER_ANDROID -TSAN_INTERCEPTOR(int, __fxstat, int version, int fd, void *buf) { - SCOPED_TSAN_INTERCEPTOR(__fxstat, version, fd, buf); - if (fd > 0) - FdAccess(thr, pc, fd); - return REAL(__fxstat)(version, fd, buf); -} -#define TSAN_MAYBE_INTERCEPT___FXSTAT TSAN_INTERCEPT(__fxstat) -#else -#define TSAN_MAYBE_INTERCEPT___FXSTAT -#endif - -TSAN_INTERCEPTOR(int, fstat, int fd, void *buf) { -#if SANITIZER_FREEBSD || SANITIZER_MAC || SANITIZER_ANDROID || SANITIZER_NETBSD - SCOPED_TSAN_INTERCEPTOR(fstat, fd, buf); - if (fd > 0) - FdAccess(thr, pc, fd); - return REAL(fstat)(fd, buf); -#else - SCOPED_TSAN_INTERCEPTOR(__fxstat, 0, fd, buf); - if (fd > 0) - FdAccess(thr, pc, fd); - return REAL(__fxstat)(0, fd, buf); -#endif -} - -#if SANITIZER_LINUX && !SANITIZER_ANDROID -TSAN_INTERCEPTOR(int, __fxstat64, int version, int fd, void *buf) { - SCOPED_TSAN_INTERCEPTOR(__fxstat64, version, fd, buf); - if (fd > 0) - FdAccess(thr, pc, fd); - return REAL(__fxstat64)(version, fd, buf); -} -#define TSAN_MAYBE_INTERCEPT___FXSTAT64 TSAN_INTERCEPT(__fxstat64) -#else -#define TSAN_MAYBE_INTERCEPT___FXSTAT64 -#endif - -#if SANITIZER_LINUX && !SANITIZER_ANDROID -TSAN_INTERCEPTOR(int, fstat64, int fd, void *buf) { - SCOPED_TSAN_INTERCEPTOR(__fxstat64, 0, fd, buf); - if (fd > 0) - FdAccess(thr, pc, fd); - return REAL(__fxstat64)(0, fd, buf); -} -#define TSAN_MAYBE_INTERCEPT_FSTAT64 TSAN_INTERCEPT(fstat64) -#else -#define TSAN_MAYBE_INTERCEPT_FSTAT64 -#endif - -TSAN_INTERCEPTOR(int, open, const char *name, int flags, int mode) { - SCOPED_TSAN_INTERCEPTOR(open, name, flags, mode); - READ_STRING(thr, pc, name, 0); - int fd = REAL(open)(name, flags, mode); - if (fd >= 0) - FdFileCreate(thr, pc, fd); - return fd; -} - -#if SANITIZER_LINUX -TSAN_INTERCEPTOR(int, open64, const char *name, int flags, int mode) { - SCOPED_TSAN_INTERCEPTOR(open64, name, flags, mode); - READ_STRING(thr, pc, name, 0); - int fd = REAL(open64)(name, flags, mode); - if (fd >= 0) - FdFileCreate(thr, pc, fd); - return fd; -} -#define TSAN_MAYBE_INTERCEPT_OPEN64 TSAN_INTERCEPT(open64) -#else -#define TSAN_MAYBE_INTERCEPT_OPEN64 -#endif - -TSAN_INTERCEPTOR(int, creat, const char *name, int mode) { - SCOPED_TSAN_INTERCEPTOR(creat, name, mode); - READ_STRING(thr, pc, name, 0); - int fd = REAL(creat)(name, mode); - if (fd >= 0) - FdFileCreate(thr, pc, fd); - return fd; -} - -#if SANITIZER_LINUX -TSAN_INTERCEPTOR(int, creat64, const char *name, int mode) { - SCOPED_TSAN_INTERCEPTOR(creat64, name, mode); - READ_STRING(thr, pc, name, 0); - int fd = REAL(creat64)(name, mode); - if (fd >= 0) - FdFileCreate(thr, pc, fd); - return fd; -} -#define TSAN_MAYBE_INTERCEPT_CREAT64 TSAN_INTERCEPT(creat64) -#else -#define TSAN_MAYBE_INTERCEPT_CREAT64 -#endif - -TSAN_INTERCEPTOR(int, dup, int oldfd) { - SCOPED_TSAN_INTERCEPTOR(dup, oldfd); - int newfd = REAL(dup)(oldfd); - if (oldfd >= 0 && newfd >= 0 && newfd != oldfd) - FdDup(thr, pc, oldfd, newfd, true); - return newfd; -} - -TSAN_INTERCEPTOR(int, dup2, int oldfd, int newfd) { - SCOPED_TSAN_INTERCEPTOR(dup2, oldfd, newfd); - int newfd2 = REAL(dup2)(oldfd, newfd); - if (oldfd >= 0 && newfd2 >= 0 && newfd2 != oldfd) - FdDup(thr, pc, oldfd, newfd2, false); - return newfd2; -} - -#if !SANITIZER_MAC -TSAN_INTERCEPTOR(int, dup3, int oldfd, int newfd, int flags) { - SCOPED_TSAN_INTERCEPTOR(dup3, oldfd, newfd, flags); - int newfd2 = REAL(dup3)(oldfd, newfd, flags); - if (oldfd >= 0 && newfd2 >= 0 && newfd2 != oldfd) - FdDup(thr, pc, oldfd, newfd2, false); - return newfd2; -} -#endif - -#if SANITIZER_LINUX -TSAN_INTERCEPTOR(int, eventfd, unsigned initval, int flags) { - SCOPED_TSAN_INTERCEPTOR(eventfd, initval, flags); - int fd = REAL(eventfd)(initval, flags); - if (fd >= 0) - FdEventCreate(thr, pc, fd); - return fd; -} -#define TSAN_MAYBE_INTERCEPT_EVENTFD TSAN_INTERCEPT(eventfd) -#else -#define TSAN_MAYBE_INTERCEPT_EVENTFD -#endif - -#if SANITIZER_LINUX -TSAN_INTERCEPTOR(int, signalfd, int fd, void *mask, int flags) { - SCOPED_TSAN_INTERCEPTOR(signalfd, fd, mask, flags); - if (fd >= 0) - FdClose(thr, pc, fd); - fd = REAL(signalfd)(fd, mask, flags); - if (fd >= 0) - FdSignalCreate(thr, pc, fd); - return fd; -} -#define TSAN_MAYBE_INTERCEPT_SIGNALFD TSAN_INTERCEPT(signalfd) -#else -#define TSAN_MAYBE_INTERCEPT_SIGNALFD -#endif - -#if SANITIZER_LINUX -TSAN_INTERCEPTOR(int, inotify_init, int fake) { - SCOPED_TSAN_INTERCEPTOR(inotify_init, fake); - int fd = REAL(inotify_init)(fake); - if (fd >= 0) - FdInotifyCreate(thr, pc, fd); - return fd; -} -#define TSAN_MAYBE_INTERCEPT_INOTIFY_INIT TSAN_INTERCEPT(inotify_init) -#else -#define TSAN_MAYBE_INTERCEPT_INOTIFY_INIT -#endif - -#if SANITIZER_LINUX -TSAN_INTERCEPTOR(int, inotify_init1, int flags) { - SCOPED_TSAN_INTERCEPTOR(inotify_init1, flags); - int fd = REAL(inotify_init1)(flags); - if (fd >= 0) - FdInotifyCreate(thr, pc, fd); - return fd; -} -#define TSAN_MAYBE_INTERCEPT_INOTIFY_INIT1 TSAN_INTERCEPT(inotify_init1) -#else -#define TSAN_MAYBE_INTERCEPT_INOTIFY_INIT1 -#endif - -TSAN_INTERCEPTOR(int, socket, int domain, int type, int protocol) { - SCOPED_TSAN_INTERCEPTOR(socket, domain, type, protocol); - int fd = REAL(socket)(domain, type, protocol); - if (fd >= 0) - FdSocketCreate(thr, pc, fd); - return fd; -} - -TSAN_INTERCEPTOR(int, socketpair, int domain, int type, int protocol, int *fd) { - SCOPED_TSAN_INTERCEPTOR(socketpair, domain, type, protocol, fd); - int res = REAL(socketpair)(domain, type, protocol, fd); - if (res == 0 && fd[0] >= 0 && fd[1] >= 0) - FdPipeCreate(thr, pc, fd[0], fd[1]); - return res; -} - -TSAN_INTERCEPTOR(int, connect, int fd, void *addr, unsigned addrlen) { - SCOPED_TSAN_INTERCEPTOR(connect, fd, addr, addrlen); - FdSocketConnecting(thr, pc, fd); - int res = REAL(connect)(fd, addr, addrlen); - if (res == 0 && fd >= 0) - FdSocketConnect(thr, pc, fd); - return res; -} - -TSAN_INTERCEPTOR(int, bind, int fd, void *addr, unsigned addrlen) { - SCOPED_TSAN_INTERCEPTOR(bind, fd, addr, addrlen); - int res = REAL(bind)(fd, addr, addrlen); - if (fd > 0 && res == 0) - FdAccess(thr, pc, fd); - return res; -} - -TSAN_INTERCEPTOR(int, listen, int fd, int backlog) { - SCOPED_TSAN_INTERCEPTOR(listen, fd, backlog); - int res = REAL(listen)(fd, backlog); - if (fd > 0 && res == 0) - FdAccess(thr, pc, fd); - return res; -} - -TSAN_INTERCEPTOR(int, close, int fd) { - SCOPED_TSAN_INTERCEPTOR(close, fd); - if (fd >= 0) - FdClose(thr, pc, fd); - return REAL(close)(fd); -} - -#if SANITIZER_LINUX -TSAN_INTERCEPTOR(int, __close, int fd) { - SCOPED_TSAN_INTERCEPTOR(__close, fd); - if (fd >= 0) - FdClose(thr, pc, fd); - return REAL(__close)(fd); -} -#define TSAN_MAYBE_INTERCEPT___CLOSE TSAN_INTERCEPT(__close) -#else -#define TSAN_MAYBE_INTERCEPT___CLOSE -#endif - -// glibc guts -#if SANITIZER_LINUX && !SANITIZER_ANDROID -TSAN_INTERCEPTOR(void, __res_iclose, void *state, bool free_addr) { - SCOPED_TSAN_INTERCEPTOR(__res_iclose, state, free_addr); - int fds[64]; - int cnt = ExtractResolvFDs(state, fds, ARRAY_SIZE(fds)); - for (int i = 0; i < cnt; i++) { - if (fds[i] > 0) - FdClose(thr, pc, fds[i]); - } - REAL(__res_iclose)(state, free_addr); -} -#define TSAN_MAYBE_INTERCEPT___RES_ICLOSE TSAN_INTERCEPT(__res_iclose) -#else -#define TSAN_MAYBE_INTERCEPT___RES_ICLOSE -#endif - -TSAN_INTERCEPTOR(int, pipe, int *pipefd) { - SCOPED_TSAN_INTERCEPTOR(pipe, pipefd); - int res = REAL(pipe)(pipefd); - if (res == 0 && pipefd[0] >= 0 && pipefd[1] >= 0) - FdPipeCreate(thr, pc, pipefd[0], pipefd[1]); - return res; -} - -#if !SANITIZER_MAC -TSAN_INTERCEPTOR(int, pipe2, int *pipefd, int flags) { - SCOPED_TSAN_INTERCEPTOR(pipe2, pipefd, flags); - int res = REAL(pipe2)(pipefd, flags); - if (res == 0 && pipefd[0] >= 0 && pipefd[1] >= 0) - FdPipeCreate(thr, pc, pipefd[0], pipefd[1]); - return res; -} -#endif - -TSAN_INTERCEPTOR(int, unlink, char *path) { - SCOPED_TSAN_INTERCEPTOR(unlink, path); - Release(thr, pc, File2addr(path)); - int res = REAL(unlink)(path); - return res; -} - -TSAN_INTERCEPTOR(void*, tmpfile, int fake) { - SCOPED_TSAN_INTERCEPTOR(tmpfile, fake); - void *res = REAL(tmpfile)(fake); - if (res) { - int fd = fileno_unlocked(res); - if (fd >= 0) - FdFileCreate(thr, pc, fd); - } - return res; -} - -#if SANITIZER_LINUX -TSAN_INTERCEPTOR(void*, tmpfile64, int fake) { - SCOPED_TSAN_INTERCEPTOR(tmpfile64, fake); - void *res = REAL(tmpfile64)(fake); - if (res) { - int fd = fileno_unlocked(res); - if (fd >= 0) - FdFileCreate(thr, pc, fd); - } - return res; -} -#define TSAN_MAYBE_INTERCEPT_TMPFILE64 TSAN_INTERCEPT(tmpfile64) -#else -#define TSAN_MAYBE_INTERCEPT_TMPFILE64 -#endif - -static void FlushStreams() { - // Flushing all the streams here may freeze the process if a child thread is - // performing file stream operations at the same time. - REAL(fflush)(stdout); - REAL(fflush)(stderr); -} - -TSAN_INTERCEPTOR(void, abort, int fake) { - SCOPED_TSAN_INTERCEPTOR(abort, fake); - FlushStreams(); - REAL(abort)(fake); -} - -TSAN_INTERCEPTOR(int, rmdir, char *path) { - SCOPED_TSAN_INTERCEPTOR(rmdir, path); - Release(thr, pc, Dir2addr(path)); - int res = REAL(rmdir)(path); - return res; -} - -TSAN_INTERCEPTOR(int, closedir, void *dirp) { - SCOPED_TSAN_INTERCEPTOR(closedir, dirp); - if (dirp) { - int fd = dirfd(dirp); - FdClose(thr, pc, fd); - } - return REAL(closedir)(dirp); -} - -#if SANITIZER_LINUX -TSAN_INTERCEPTOR(int, epoll_create, int size) { - SCOPED_TSAN_INTERCEPTOR(epoll_create, size); - int fd = REAL(epoll_create)(size); - if (fd >= 0) - FdPollCreate(thr, pc, fd); - return fd; -} - -TSAN_INTERCEPTOR(int, epoll_create1, int flags) { - SCOPED_TSAN_INTERCEPTOR(epoll_create1, flags); - int fd = REAL(epoll_create1)(flags); - if (fd >= 0) - FdPollCreate(thr, pc, fd); - return fd; -} - -TSAN_INTERCEPTOR(int, epoll_ctl, int epfd, int op, int fd, void *ev) { - SCOPED_TSAN_INTERCEPTOR(epoll_ctl, epfd, op, fd, ev); - if (epfd >= 0) - FdAccess(thr, pc, epfd); - if (epfd >= 0 && fd >= 0) - FdAccess(thr, pc, fd); - if (op == EPOLL_CTL_ADD && epfd >= 0) - FdRelease(thr, pc, epfd); - int res = REAL(epoll_ctl)(epfd, op, fd, ev); - return res; -} - -TSAN_INTERCEPTOR(int, epoll_wait, int epfd, void *ev, int cnt, int timeout) { - SCOPED_TSAN_INTERCEPTOR(epoll_wait, epfd, ev, cnt, timeout); - if (epfd >= 0) - FdAccess(thr, pc, epfd); - int res = BLOCK_REAL(epoll_wait)(epfd, ev, cnt, timeout); - if (res > 0 && epfd >= 0) - FdAcquire(thr, pc, epfd); - return res; -} - -TSAN_INTERCEPTOR(int, epoll_pwait, int epfd, void *ev, int cnt, int timeout, - void *sigmask) { - SCOPED_TSAN_INTERCEPTOR(epoll_pwait, epfd, ev, cnt, timeout, sigmask); - if (epfd >= 0) - FdAccess(thr, pc, epfd); - int res = BLOCK_REAL(epoll_pwait)(epfd, ev, cnt, timeout, sigmask); - if (res > 0 && epfd >= 0) - FdAcquire(thr, pc, epfd); - return res; -} - -#define TSAN_MAYBE_INTERCEPT_EPOLL \ - TSAN_INTERCEPT(epoll_create); \ - TSAN_INTERCEPT(epoll_create1); \ - TSAN_INTERCEPT(epoll_ctl); \ - TSAN_INTERCEPT(epoll_wait); \ - TSAN_INTERCEPT(epoll_pwait) -#else -#define TSAN_MAYBE_INTERCEPT_EPOLL -#endif - -// The following functions are intercepted merely to process pending signals. -// If program blocks signal X, we must deliver the signal before the function -// returns. Similarly, if program unblocks a signal (or returns from sigsuspend) -// it's better to deliver the signal straight away. -TSAN_INTERCEPTOR(int, sigsuspend, const __sanitizer_sigset_t *mask) { - SCOPED_TSAN_INTERCEPTOR(sigsuspend, mask); - return REAL(sigsuspend)(mask); -} - -TSAN_INTERCEPTOR(int, sigblock, int mask) { - SCOPED_TSAN_INTERCEPTOR(sigblock, mask); - return REAL(sigblock)(mask); -} - -TSAN_INTERCEPTOR(int, sigsetmask, int mask) { - SCOPED_TSAN_INTERCEPTOR(sigsetmask, mask); - return REAL(sigsetmask)(mask); -} - -TSAN_INTERCEPTOR(int, pthread_sigmask, int how, const __sanitizer_sigset_t *set, - __sanitizer_sigset_t *oldset) { - SCOPED_TSAN_INTERCEPTOR(pthread_sigmask, how, set, oldset); - return REAL(pthread_sigmask)(how, set, oldset); -} - -namespace __tsan { - -static void CallUserSignalHandler(ThreadState *thr, bool sync, bool acquire, - bool sigact, int sig, - __sanitizer_siginfo *info, void *uctx) { - __sanitizer_sigaction *sigactions = interceptor_ctx()->sigactions; - if (acquire) - Acquire(thr, 0, (uptr)&sigactions[sig]); - // Signals are generally asynchronous, so if we receive a signals when - // ignores are enabled we should disable ignores. This is critical for sync - // and interceptors, because otherwise we can miss syncronization and report - // false races. - int ignore_reads_and_writes = thr->ignore_reads_and_writes; - int ignore_interceptors = thr->ignore_interceptors; - int ignore_sync = thr->ignore_sync; - if (!ctx->after_multithreaded_fork) { - thr->ignore_reads_and_writes = 0; - thr->fast_state.ClearIgnoreBit(); - thr->ignore_interceptors = 0; - thr->ignore_sync = 0; - } - // Ensure that the handler does not spoil errno. - const int saved_errno = errno; - errno = 99; - // This code races with sigaction. Be careful to not read sa_sigaction twice. - // Also need to remember pc for reporting before the call, - // because the handler can reset it. - volatile uptr pc = - sigact ? (uptr)sigactions[sig].sigaction : (uptr)sigactions[sig].handler; - if (pc != sig_dfl && pc != sig_ign) { - if (sigact) - ((__sanitizer_sigactionhandler_ptr)pc)(sig, info, uctx); - else - ((__sanitizer_sighandler_ptr)pc)(sig); - } - if (!ctx->after_multithreaded_fork) { - thr->ignore_reads_and_writes = ignore_reads_and_writes; - if (ignore_reads_and_writes) - thr->fast_state.SetIgnoreBit(); - thr->ignore_interceptors = ignore_interceptors; - thr->ignore_sync = ignore_sync; - } - // We do not detect errno spoiling for SIGTERM, - // because some SIGTERM handlers do spoil errno but reraise SIGTERM, - // tsan reports false positive in such case. - // It's difficult to properly detect this situation (reraise), - // because in async signal processing case (when handler is called directly - // from rtl_generic_sighandler) we have not yet received the reraised - // signal; and it looks too fragile to intercept all ways to reraise a signal. - if (flags()->report_bugs && !sync && sig != SIGTERM && errno != 99) { - VarSizeStackTrace stack; - // StackTrace::GetNestInstructionPc(pc) is used because return address is - // expected, OutputReport() will undo this. - ObtainCurrentStack(thr, StackTrace::GetNextInstructionPc(pc), &stack); - ThreadRegistryLock l(ctx->thread_registry); - ScopedReport rep(ReportTypeErrnoInSignal); - if (!IsFiredSuppression(ctx, ReportTypeErrnoInSignal, stack)) { - rep.AddStack(stack, true); - OutputReport(thr, rep); - } - } - errno = saved_errno; -} - -void ProcessPendingSignals(ThreadState *thr) { - ThreadSignalContext *sctx = SigCtx(thr); - if (sctx == 0 || - atomic_load(&sctx->have_pending_signals, memory_order_relaxed) == 0) - return; - atomic_store(&sctx->have_pending_signals, 0, memory_order_relaxed); - 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); - CHECK_EQ(res, 0); - for (int sig = 0; sig < kSigCount; sig++) { - SignalDesc *signal = &sctx->pending_signals[sig]; - if (signal->armed) { - signal->armed = false; - CallUserSignalHandler(thr, false, true, signal->sigaction, sig, - &signal->siginfo, &signal->ctx); - } - } - res = REAL(pthread_sigmask)(SIG_SETMASK, &sctx->oldset, 0); - CHECK_EQ(res, 0); - atomic_fetch_add(&thr->in_signal_handler, -1, memory_order_relaxed); -} - -} // namespace __tsan - -static bool is_sync_signal(ThreadSignalContext *sctx, int sig) { - return sig == SIGSEGV || sig == SIGBUS || sig == SIGILL || - sig == SIGABRT || sig == SIGFPE || sig == SIGPIPE || sig == SIGSYS || - // If we are sending signal to ourselves, we must process it now. - (sctx && sig == sctx->int_signal_send); -} - -void ALWAYS_INLINE rtl_generic_sighandler(bool sigact, int sig, - __sanitizer_siginfo *info, - void *ctx) { - cur_thread_init(); - ThreadState *thr = cur_thread(); - ThreadSignalContext *sctx = SigCtx(thr); - if (sig < 0 || sig >= kSigCount) { - VPrintf(1, "ThreadSanitizer: ignoring signal %d\n", sig); - return; - } - // Don't mess with synchronous signals. - const bool sync = is_sync_signal(sctx, sig); - if (sync || - // If we are in blocking function, we can safely process it now - // (but check if we are in a recursive interceptor, - // i.e. pthread_join()->munmap()). - (sctx && atomic_load(&sctx->in_blocking_func, memory_order_relaxed))) { - atomic_fetch_add(&thr->in_signal_handler, 1, memory_order_relaxed); - if (sctx && atomic_load(&sctx->in_blocking_func, memory_order_relaxed)) { - atomic_store(&sctx->in_blocking_func, 0, memory_order_relaxed); - CallUserSignalHandler(thr, sync, true, sigact, sig, info, ctx); - atomic_store(&sctx->in_blocking_func, 1, memory_order_relaxed); - } else { - // Be very conservative with when we do acquire in this case. - // It's unsafe to do acquire in async handlers, because ThreadState - // can be in inconsistent state. - // SIGSYS looks relatively safe -- it's synchronous and can actually - // need some global state. - bool acq = (sig == SIGSYS); - CallUserSignalHandler(thr, sync, acq, sigact, sig, info, ctx); - } - atomic_fetch_add(&thr->in_signal_handler, -1, memory_order_relaxed); - return; - } - - if (sctx == 0) - return; - SignalDesc *signal = &sctx->pending_signals[sig]; - if (signal->armed == false) { - signal->armed = true; - signal->sigaction = sigact; - if (info) - internal_memcpy(&signal->siginfo, info, sizeof(*info)); - if (ctx) - internal_memcpy(&signal->ctx, ctx, sizeof(signal->ctx)); - atomic_store(&sctx->have_pending_signals, 1, memory_order_relaxed); - } -} - -static void rtl_sighandler(int sig) { - rtl_generic_sighandler(false, sig, 0, 0); -} - -static void rtl_sigaction(int sig, __sanitizer_siginfo *info, void *ctx) { - rtl_generic_sighandler(true, sig, info, ctx); -} - -TSAN_INTERCEPTOR(int, raise, int sig) { - SCOPED_TSAN_INTERCEPTOR(raise, sig); - ThreadSignalContext *sctx = SigCtx(thr); - CHECK_NE(sctx, 0); - int prev = sctx->int_signal_send; - sctx->int_signal_send = sig; - int res = REAL(raise)(sig); - CHECK_EQ(sctx->int_signal_send, sig); - sctx->int_signal_send = prev; - return res; -} - -TSAN_INTERCEPTOR(int, kill, int pid, int sig) { - SCOPED_TSAN_INTERCEPTOR(kill, pid, sig); - ThreadSignalContext *sctx = SigCtx(thr); - CHECK_NE(sctx, 0); - int prev = sctx->int_signal_send; - if (pid == (int)internal_getpid()) { - sctx->int_signal_send = sig; - } - int res = REAL(kill)(pid, sig); - if (pid == (int)internal_getpid()) { - CHECK_EQ(sctx->int_signal_send, sig); - sctx->int_signal_send = prev; - } - return res; -} - -TSAN_INTERCEPTOR(int, pthread_kill, void *tid, int sig) { - SCOPED_TSAN_INTERCEPTOR(pthread_kill, tid, sig); - ThreadSignalContext *sctx = SigCtx(thr); - CHECK_NE(sctx, 0); - int prev = sctx->int_signal_send; - if (tid == pthread_self()) { - sctx->int_signal_send = sig; - } - int res = REAL(pthread_kill)(tid, sig); - if (tid == pthread_self()) { - CHECK_EQ(sctx->int_signal_send, sig); - sctx->int_signal_send = prev; - } - return res; -} - -TSAN_INTERCEPTOR(int, gettimeofday, void *tv, void *tz) { - SCOPED_TSAN_INTERCEPTOR(gettimeofday, tv, tz); - // It's intercepted merely to process pending signals. - return REAL(gettimeofday)(tv, tz); -} - -TSAN_INTERCEPTOR(int, getaddrinfo, void *node, void *service, - void *hints, void *rv) { - SCOPED_TSAN_INTERCEPTOR(getaddrinfo, node, service, hints, rv); - // We miss atomic synchronization in getaddrinfo, - // and can report false race between malloc and free - // inside of getaddrinfo. So ignore memory accesses. - ThreadIgnoreBegin(thr, pc); - int res = REAL(getaddrinfo)(node, service, hints, rv); - ThreadIgnoreEnd(thr, pc); - return res; -} - -TSAN_INTERCEPTOR(int, fork, int fake) { - if (in_symbolizer()) - return REAL(fork)(fake); - SCOPED_INTERCEPTOR_RAW(fork, fake); - ForkBefore(thr, pc); - int pid; - { - // On OS X, REAL(fork) can call intercepted functions (OSSpinLockLock), and - // we'll assert in CheckNoLocks() unless we ignore interceptors. - ScopedIgnoreInterceptors ignore; - pid = REAL(fork)(fake); - } - if (pid == 0) { - // child - ForkChildAfter(thr, pc); - FdOnFork(thr, pc); - } else if (pid > 0) { - // parent - ForkParentAfter(thr, pc); - } else { - // error - ForkParentAfter(thr, pc); - } - return pid; -} - -TSAN_INTERCEPTOR(int, vfork, int fake) { - // Some programs (e.g. openjdk) call close for all file descriptors - // in the child process. Under tsan it leads to false positives, because - // address space is shared, so the parent process also thinks that - // the descriptors are closed (while they are actually not). - // This leads to false positives due to missed synchronization. - // Strictly saying this is undefined behavior, because vfork child is not - // allowed to call any functions other than exec/exit. But this is what - // openjdk does, so we want to handle it. - // We could disable interceptors in the child process. But it's not possible - // to simply intercept and wrap vfork, because vfork child is not allowed - // to return from the function that calls vfork, and that's exactly what - // we would do. So this would require some assembly trickery as well. - // Instead we simply turn vfork into fork. - return WRAP(fork)(fake); -} - -#if !SANITIZER_MAC && !SANITIZER_ANDROID -typedef int (*dl_iterate_phdr_cb_t)(__sanitizer_dl_phdr_info *info, SIZE_T size, - void *data); -struct dl_iterate_phdr_data { - ThreadState *thr; - uptr pc; - dl_iterate_phdr_cb_t cb; - void *data; -}; - -static bool IsAppNotRodata(uptr addr) { - return IsAppMem(addr) && *(u64*)MemToShadow(addr) != kShadowRodata; -} - -static int dl_iterate_phdr_cb(__sanitizer_dl_phdr_info *info, SIZE_T size, - void *data) { - dl_iterate_phdr_data *cbdata = (dl_iterate_phdr_data *)data; - // dlopen/dlclose allocate/free dynamic-linker-internal memory, which is later - // accessible in dl_iterate_phdr callback. But we don't see synchronization - // inside of dynamic linker, so we "unpoison" it here in order to not - // produce false reports. Ignoring malloc/free in dlopen/dlclose is not enough - // because some libc functions call __libc_dlopen. - if (info && IsAppNotRodata((uptr)info->dlpi_name)) - MemoryResetRange(cbdata->thr, cbdata->pc, (uptr)info->dlpi_name, - internal_strlen(info->dlpi_name)); - int res = cbdata->cb(info, size, cbdata->data); - // Perform the check one more time in case info->dlpi_name was overwritten - // by user callback. - if (info && IsAppNotRodata((uptr)info->dlpi_name)) - MemoryResetRange(cbdata->thr, cbdata->pc, (uptr)info->dlpi_name, - internal_strlen(info->dlpi_name)); - return res; -} - -TSAN_INTERCEPTOR(int, dl_iterate_phdr, dl_iterate_phdr_cb_t cb, void *data) { - SCOPED_TSAN_INTERCEPTOR(dl_iterate_phdr, cb, data); - dl_iterate_phdr_data cbdata; - cbdata.thr = thr; - cbdata.pc = pc; - cbdata.cb = cb; - cbdata.data = data; - int res = REAL(dl_iterate_phdr)(dl_iterate_phdr_cb, &cbdata); - return res; -} -#endif - -static int OnExit(ThreadState *thr) { - int status = Finalize(thr); - FlushStreams(); - return status; -} - -struct TsanInterceptorContext { - ThreadState *thr; - const uptr caller_pc; - const uptr pc; -}; - -#if !SANITIZER_MAC -static void HandleRecvmsg(ThreadState *thr, uptr pc, - __sanitizer_msghdr *msg) { - int fds[64]; - int cnt = ExtractRecvmsgFDs(msg, fds, ARRAY_SIZE(fds)); - for (int i = 0; i < cnt; i++) - FdEventCreate(thr, pc, fds[i]); -} -#endif - -#include "sanitizer_common/sanitizer_platform_interceptors.h" -// Causes interceptor recursion (getaddrinfo() and fopen()) -#undef SANITIZER_INTERCEPT_GETADDRINFO -// We define our own. -#if SANITIZER_INTERCEPT_TLS_GET_ADDR -#define NEED_TLS_GET_ADDR -#endif -#undef SANITIZER_INTERCEPT_TLS_GET_ADDR -#undef SANITIZER_INTERCEPT_PTHREAD_SIGMASK - -#define COMMON_INTERCEPT_FUNCTION(name) INTERCEPT_FUNCTION(name) -#define COMMON_INTERCEPT_FUNCTION_VER(name, ver) \ - INTERCEPT_FUNCTION_VER(name, ver) - -#define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \ - MemoryAccessRange(((TsanInterceptorContext *)ctx)->thr, \ - ((TsanInterceptorContext *)ctx)->pc, (uptr)ptr, size, \ - true) - -#define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \ - MemoryAccessRange(((TsanInterceptorContext *) ctx)->thr, \ - ((TsanInterceptorContext *) ctx)->pc, (uptr) ptr, size, \ - false) - -#define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \ - SCOPED_TSAN_INTERCEPTOR(func, __VA_ARGS__); \ - TsanInterceptorContext _ctx = {thr, caller_pc, pc}; \ - ctx = (void *)&_ctx; \ - (void) ctx; - -#define COMMON_INTERCEPTOR_ENTER_NOIGNORE(ctx, func, ...) \ - SCOPED_INTERCEPTOR_RAW(func, __VA_ARGS__); \ - TsanInterceptorContext _ctx = {thr, caller_pc, pc}; \ - ctx = (void *)&_ctx; \ - (void) ctx; - -#define COMMON_INTERCEPTOR_FILE_OPEN(ctx, file, path) \ - if (path) \ - Acquire(thr, pc, File2addr(path)); \ - if (file) { \ - int fd = fileno_unlocked(file); \ - if (fd >= 0) FdFileCreate(thr, pc, fd); \ - } - -#define COMMON_INTERCEPTOR_FILE_CLOSE(ctx, file) \ - if (file) { \ - int fd = fileno_unlocked(file); \ - if (fd >= 0) FdClose(thr, pc, fd); \ - } - -#define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, handle) \ - libignore()->OnLibraryLoaded(filename) - -#define COMMON_INTERCEPTOR_LIBRARY_UNLOADED() \ - libignore()->OnLibraryUnloaded() - -#define COMMON_INTERCEPTOR_ACQUIRE(ctx, u) \ - Acquire(((TsanInterceptorContext *) ctx)->thr, pc, u) - -#define COMMON_INTERCEPTOR_RELEASE(ctx, u) \ - Release(((TsanInterceptorContext *) ctx)->thr, pc, u) - -#define COMMON_INTERCEPTOR_DIR_ACQUIRE(ctx, path) \ - Acquire(((TsanInterceptorContext *) ctx)->thr, pc, Dir2addr(path)) - -#define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) \ - FdAcquire(((TsanInterceptorContext *) ctx)->thr, pc, fd) - -#define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) \ - FdRelease(((TsanInterceptorContext *) ctx)->thr, pc, fd) - -#define COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd) \ - FdAccess(((TsanInterceptorContext *) ctx)->thr, pc, fd) - -#define COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, newfd) \ - FdSocketAccept(((TsanInterceptorContext *) ctx)->thr, pc, fd, newfd) - -#define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name) \ - ThreadSetName(((TsanInterceptorContext *) ctx)->thr, name) - -#define COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name) \ - __tsan::ctx->thread_registry->SetThreadNameByUserId(thread, name) - -#define COMMON_INTERCEPTOR_BLOCK_REAL(name) BLOCK_REAL(name) - -#define COMMON_INTERCEPTOR_ON_EXIT(ctx) \ - OnExit(((TsanInterceptorContext *) ctx)->thr) - -#define COMMON_INTERCEPTOR_MUTEX_PRE_LOCK(ctx, m) \ - MutexPreLock(((TsanInterceptorContext *)ctx)->thr, \ - ((TsanInterceptorContext *)ctx)->pc, (uptr)m) - -#define COMMON_INTERCEPTOR_MUTEX_POST_LOCK(ctx, m) \ - MutexPostLock(((TsanInterceptorContext *)ctx)->thr, \ - ((TsanInterceptorContext *)ctx)->pc, (uptr)m) - -#define COMMON_INTERCEPTOR_MUTEX_UNLOCK(ctx, m) \ - MutexUnlock(((TsanInterceptorContext *)ctx)->thr, \ - ((TsanInterceptorContext *)ctx)->pc, (uptr)m) - -#define COMMON_INTERCEPTOR_MUTEX_REPAIR(ctx, m) \ - MutexRepair(((TsanInterceptorContext *)ctx)->thr, \ - ((TsanInterceptorContext *)ctx)->pc, (uptr)m) - -#define COMMON_INTERCEPTOR_MUTEX_INVALID(ctx, m) \ - MutexInvalidAccess(((TsanInterceptorContext *)ctx)->thr, \ - ((TsanInterceptorContext *)ctx)->pc, (uptr)m) - -#define COMMON_INTERCEPTOR_MMAP_IMPL(ctx, mmap, addr, sz, prot, flags, fd, \ - off) \ - do { \ - return mmap_interceptor(thr, pc, REAL(mmap), addr, sz, prot, flags, fd, \ - off); \ - } while (false) - -#if !SANITIZER_MAC -#define COMMON_INTERCEPTOR_HANDLE_RECVMSG(ctx, msg) \ - HandleRecvmsg(((TsanInterceptorContext *)ctx)->thr, \ - ((TsanInterceptorContext *)ctx)->pc, msg) -#endif - -#define COMMON_INTERCEPTOR_GET_TLS_RANGE(begin, end) \ - if (TsanThread *t = GetCurrentThread()) { \ - *begin = t->tls_begin(); \ - *end = t->tls_end(); \ - } else { \ - *begin = *end = 0; \ - } - -#define COMMON_INTERCEPTOR_USER_CALLBACK_START() \ - SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START() - -#define COMMON_INTERCEPTOR_USER_CALLBACK_END() \ - SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END() - -#include "sanitizer_common/sanitizer_common_interceptors.inc" - -static int sigaction_impl(int sig, const __sanitizer_sigaction *act, - __sanitizer_sigaction *old); -static __sanitizer_sighandler_ptr signal_impl(int sig, - __sanitizer_sighandler_ptr h); - -#define SIGNAL_INTERCEPTOR_SIGACTION_IMPL(signo, act, oldact) \ - { return sigaction_impl(signo, act, oldact); } - -#define SIGNAL_INTERCEPTOR_SIGNAL_IMPL(func, signo, handler) \ - { return (uptr)signal_impl(signo, (__sanitizer_sighandler_ptr)handler); } - -#include "sanitizer_common/sanitizer_signal_interceptors.inc" - -int sigaction_impl(int sig, const __sanitizer_sigaction *act, - __sanitizer_sigaction *old) { - // Note: if we call REAL(sigaction) directly for any reason without proxying - // the signal handler through rtl_sigaction, very bad things will happen. - // The handler will run synchronously and corrupt tsan per-thread state. - SCOPED_INTERCEPTOR_RAW(sigaction, sig, act, old); - __sanitizer_sigaction *sigactions = interceptor_ctx()->sigactions; - __sanitizer_sigaction old_stored; - if (old) internal_memcpy(&old_stored, &sigactions[sig], sizeof(old_stored)); - __sanitizer_sigaction newact; - if (act) { - // Copy act into sigactions[sig]. - // Can't use struct copy, because compiler can emit call to memcpy. - // Can't use internal_memcpy, because it copies byte-by-byte, - // and signal handler reads the handler concurrently. It it can read - // some bytes from old value and some bytes from new value. - // Use volatile to prevent insertion of memcpy. - sigactions[sig].handler = - *(volatile __sanitizer_sighandler_ptr const *)&act->handler; - sigactions[sig].sa_flags = *(volatile int const *)&act->sa_flags; - internal_memcpy(&sigactions[sig].sa_mask, &act->sa_mask, - sizeof(sigactions[sig].sa_mask)); -#if !SANITIZER_FREEBSD && !SANITIZER_MAC && !SANITIZER_NETBSD - sigactions[sig].sa_restorer = act->sa_restorer; -#endif - internal_memcpy(&newact, act, sizeof(newact)); - internal_sigfillset(&newact.sa_mask); - if ((uptr)act->handler != sig_ign && (uptr)act->handler != sig_dfl) { - if (newact.sa_flags & SA_SIGINFO) - newact.sigaction = rtl_sigaction; - else - newact.handler = rtl_sighandler; - } - ReleaseStore(thr, pc, (uptr)&sigactions[sig]); - act = &newact; - } - int res = REAL(sigaction)(sig, act, old); - if (res == 0 && old) { - uptr cb = (uptr)old->sigaction; - if (cb == (uptr)rtl_sigaction || cb == (uptr)rtl_sighandler) { - internal_memcpy(old, &old_stored, sizeof(*old)); - } - } - return res; -} - -static __sanitizer_sighandler_ptr signal_impl(int sig, - __sanitizer_sighandler_ptr h) { - __sanitizer_sigaction act; - act.handler = h; - internal_memset(&act.sa_mask, -1, sizeof(act.sa_mask)); - act.sa_flags = 0; - __sanitizer_sigaction old; - int res = sigaction_symname(sig, &act, &old); - if (res) return (__sanitizer_sighandler_ptr)sig_err; - return old.handler; -} - -#define TSAN_SYSCALL() \ - ThreadState *thr = cur_thread(); \ - if (thr->ignore_interceptors) \ - return; \ - ScopedSyscall scoped_syscall(thr) \ -/**/ - -struct ScopedSyscall { - ThreadState *thr; - - explicit ScopedSyscall(ThreadState *thr) - : thr(thr) { - Initialize(thr); - } - - ~ScopedSyscall() { - ProcessPendingSignals(thr); - } -}; - -#if !SANITIZER_FREEBSD && !SANITIZER_MAC -static void syscall_access_range(uptr pc, uptr p, uptr s, bool write) { - TSAN_SYSCALL(); - MemoryAccessRange(thr, pc, p, s, write); -} - -static void syscall_acquire(uptr pc, uptr addr) { - TSAN_SYSCALL(); - Acquire(thr, pc, addr); - DPrintf("syscall_acquire(%p)\n", addr); -} - -static void syscall_release(uptr pc, uptr addr) { - TSAN_SYSCALL(); - DPrintf("syscall_release(%p)\n", addr); - Release(thr, pc, addr); -} - -static void syscall_fd_close(uptr pc, int fd) { - TSAN_SYSCALL(); - FdClose(thr, pc, fd); -} - -static USED void syscall_fd_acquire(uptr pc, int fd) { - TSAN_SYSCALL(); - FdAcquire(thr, pc, fd); - DPrintf("syscall_fd_acquire(%p)\n", fd); -} - -static USED void syscall_fd_release(uptr pc, int fd) { - TSAN_SYSCALL(); - DPrintf("syscall_fd_release(%p)\n", fd); - FdRelease(thr, pc, fd); -} - -static void syscall_pre_fork(uptr pc) { - TSAN_SYSCALL(); - ForkBefore(thr, pc); -} - -static void syscall_post_fork(uptr pc, int pid) { - TSAN_SYSCALL(); - if (pid == 0) { - // child - ForkChildAfter(thr, pc); - FdOnFork(thr, pc); - } else if (pid > 0) { - // parent - ForkParentAfter(thr, pc); - } else { - // error - ForkParentAfter(thr, pc); - } -} -#endif - -#define COMMON_SYSCALL_PRE_READ_RANGE(p, s) \ - syscall_access_range(GET_CALLER_PC(), (uptr)(p), (uptr)(s), false) - -#define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) \ - syscall_access_range(GET_CALLER_PC(), (uptr)(p), (uptr)(s), true) - -#define COMMON_SYSCALL_POST_READ_RANGE(p, s) \ - do { \ - (void)(p); \ - (void)(s); \ - } while (false) - -#define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) \ - do { \ - (void)(p); \ - (void)(s); \ - } while (false) - -#define COMMON_SYSCALL_ACQUIRE(addr) \ - syscall_acquire(GET_CALLER_PC(), (uptr)(addr)) - -#define COMMON_SYSCALL_RELEASE(addr) \ - syscall_release(GET_CALLER_PC(), (uptr)(addr)) - -#define COMMON_SYSCALL_FD_CLOSE(fd) syscall_fd_close(GET_CALLER_PC(), fd) - -#define COMMON_SYSCALL_FD_ACQUIRE(fd) syscall_fd_acquire(GET_CALLER_PC(), fd) - -#define COMMON_SYSCALL_FD_RELEASE(fd) syscall_fd_release(GET_CALLER_PC(), fd) - -#define COMMON_SYSCALL_PRE_FORK() \ - syscall_pre_fork(GET_CALLER_PC()) - -#define COMMON_SYSCALL_POST_FORK(res) \ - syscall_post_fork(GET_CALLER_PC(), res) - -#include "sanitizer_common/sanitizer_common_syscalls.inc" -#include "sanitizer_common/sanitizer_syscalls_netbsd.inc" - -#ifdef NEED_TLS_GET_ADDR -// Define own interceptor instead of sanitizer_common's for three reasons: -// 1. It must not process pending signals. -// Signal handlers may contain MOVDQA instruction (see below). -// 2. It must be as simple as possible to not contain MOVDQA. -// 3. Sanitizer_common version uses COMMON_INTERCEPTOR_INITIALIZE_RANGE which -// is empty for tsan (meant only for msan). -// Note: __tls_get_addr can be called with mis-aligned stack due to: -// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58066 -// So the interceptor must work with mis-aligned stack, in particular, does not -// execute MOVDQA with stack addresses. -TSAN_INTERCEPTOR(void *, __tls_get_addr, void *arg) { - void *res = REAL(__tls_get_addr)(arg); - ThreadState *thr = cur_thread(); - if (!thr) - return res; - DTLS::DTV *dtv = DTLS_on_tls_get_addr(arg, res, thr->tls_addr, - thr->tls_addr + thr->tls_size); - if (!dtv) - return res; - // New DTLS block has been allocated. - MemoryResetRange(thr, 0, dtv->beg, dtv->size); - return res; -} -#endif - -#if SANITIZER_NETBSD -TSAN_INTERCEPTOR(void, _lwp_exit) { - SCOPED_TSAN_INTERCEPTOR(_lwp_exit); - DestroyThreadState(); - REAL(_lwp_exit)(); -} -#define TSAN_MAYBE_INTERCEPT__LWP_EXIT TSAN_INTERCEPT(_lwp_exit) -#else -#define TSAN_MAYBE_INTERCEPT__LWP_EXIT -#endif - -#if SANITIZER_FREEBSD -TSAN_INTERCEPTOR(void, thr_exit, tid_t *state) { - SCOPED_TSAN_INTERCEPTOR(thr_exit, state); - DestroyThreadState(); - REAL(thr_exit(state)); -} -#define TSAN_MAYBE_INTERCEPT_THR_EXIT TSAN_INTERCEPT(thr_exit) -#else -#define TSAN_MAYBE_INTERCEPT_THR_EXIT -#endif - -TSAN_INTERCEPTOR_NETBSD_ALIAS(int, cond_init, void *c, void *a) -TSAN_INTERCEPTOR_NETBSD_ALIAS(int, cond_signal, void *c) -TSAN_INTERCEPTOR_NETBSD_ALIAS(int, cond_broadcast, void *c) -TSAN_INTERCEPTOR_NETBSD_ALIAS(int, cond_wait, void *c, void *m) -TSAN_INTERCEPTOR_NETBSD_ALIAS(int, cond_destroy, void *c) -TSAN_INTERCEPTOR_NETBSD_ALIAS(int, mutex_init, void *m, void *a) -TSAN_INTERCEPTOR_NETBSD_ALIAS(int, mutex_destroy, void *m) -TSAN_INTERCEPTOR_NETBSD_ALIAS(int, mutex_trylock, void *m) -TSAN_INTERCEPTOR_NETBSD_ALIAS(int, rwlock_init, void *m, void *a) -TSAN_INTERCEPTOR_NETBSD_ALIAS(int, rwlock_destroy, void *m) -TSAN_INTERCEPTOR_NETBSD_ALIAS(int, rwlock_rdlock, void *m) -TSAN_INTERCEPTOR_NETBSD_ALIAS(int, rwlock_tryrdlock, void *m) -TSAN_INTERCEPTOR_NETBSD_ALIAS(int, rwlock_wrlock, void *m) -TSAN_INTERCEPTOR_NETBSD_ALIAS(int, rwlock_trywrlock, void *m) -TSAN_INTERCEPTOR_NETBSD_ALIAS(int, rwlock_unlock, void *m) -TSAN_INTERCEPTOR_NETBSD_ALIAS_THR(int, once, void *o, void (*f)()) -TSAN_INTERCEPTOR_NETBSD_ALIAS_THR2(int, sigsetmask, sigmask, int a, void *b, - void *c) - -namespace __tsan { - -static void finalize(void *arg) { - ThreadState *thr = cur_thread(); - int status = Finalize(thr); - // Make sure the output is not lost. - FlushStreams(); - if (status) - Die(); -} - -#if !SANITIZER_MAC && !SANITIZER_ANDROID -static void unreachable() { - Report("FATAL: ThreadSanitizer: unreachable called\n"); - Die(); -} -#endif - -// Define default implementation since interception of libdispatch is optional. -SANITIZER_WEAK_ATTRIBUTE void InitializeLibdispatchInterceptors() {} - -void InitializeInterceptors() { -#if !SANITIZER_MAC - // We need to setup it early, because functions like dlsym() can call it. - REAL(memset) = internal_memset; - REAL(memcpy) = internal_memcpy; -#endif - - // Instruct libc malloc to consume less memory. -#if SANITIZER_LINUX - mallopt(1, 0); // M_MXFAST - mallopt(-3, 32*1024); // M_MMAP_THRESHOLD -#endif - - new(interceptor_ctx()) InterceptorContext(); - - InitializeCommonInterceptors(); - InitializeSignalInterceptors(); - InitializeLibdispatchInterceptors(); - -#if !SANITIZER_MAC - // We can not use TSAN_INTERCEPT to get setjmp addr, - // because it does &setjmp and setjmp is not present in some versions of libc. - using __interception::InterceptFunction; - InterceptFunction(TSAN_STRING_SETJMP, (uptr*)&REAL(setjmp_symname), 0, 0); - InterceptFunction("_setjmp", (uptr*)&REAL(_setjmp), 0, 0); - InterceptFunction(TSAN_STRING_SIGSETJMP, (uptr*)&REAL(sigsetjmp_symname), 0, - 0); -#if !SANITIZER_NETBSD - InterceptFunction("__sigsetjmp", (uptr*)&REAL(__sigsetjmp), 0, 0); -#endif -#endif - - TSAN_INTERCEPT(longjmp_symname); - TSAN_INTERCEPT(siglongjmp_symname); -#if SANITIZER_NETBSD - TSAN_INTERCEPT(_longjmp); -#endif - - TSAN_INTERCEPT(malloc); - TSAN_INTERCEPT(__libc_memalign); - TSAN_INTERCEPT(calloc); - TSAN_INTERCEPT(realloc); - TSAN_INTERCEPT(reallocarray); - TSAN_INTERCEPT(free); - TSAN_INTERCEPT(cfree); - TSAN_INTERCEPT(munmap); - TSAN_MAYBE_INTERCEPT_MEMALIGN; - TSAN_INTERCEPT(valloc); - TSAN_MAYBE_INTERCEPT_PVALLOC; - TSAN_INTERCEPT(posix_memalign); - - TSAN_INTERCEPT(strcpy); // NOLINT - TSAN_INTERCEPT(strncpy); - TSAN_INTERCEPT(strdup); - - TSAN_INTERCEPT(pthread_create); - TSAN_INTERCEPT(pthread_join); - TSAN_INTERCEPT(pthread_detach); - TSAN_INTERCEPT(pthread_exit); - #if SANITIZER_LINUX - TSAN_INTERCEPT(pthread_tryjoin_np); - TSAN_INTERCEPT(pthread_timedjoin_np); - #endif - - TSAN_INTERCEPT_VER(pthread_cond_init, PTHREAD_ABI_BASE); - TSAN_INTERCEPT_VER(pthread_cond_signal, PTHREAD_ABI_BASE); - TSAN_INTERCEPT_VER(pthread_cond_broadcast, PTHREAD_ABI_BASE); - TSAN_INTERCEPT_VER(pthread_cond_wait, PTHREAD_ABI_BASE); - TSAN_INTERCEPT_VER(pthread_cond_timedwait, PTHREAD_ABI_BASE); - TSAN_INTERCEPT_VER(pthread_cond_destroy, PTHREAD_ABI_BASE); - - TSAN_INTERCEPT(pthread_mutex_init); - TSAN_INTERCEPT(pthread_mutex_destroy); - TSAN_INTERCEPT(pthread_mutex_trylock); - TSAN_INTERCEPT(pthread_mutex_timedlock); - - TSAN_INTERCEPT(pthread_spin_init); - TSAN_INTERCEPT(pthread_spin_destroy); - TSAN_INTERCEPT(pthread_spin_lock); - TSAN_INTERCEPT(pthread_spin_trylock); - TSAN_INTERCEPT(pthread_spin_unlock); - - TSAN_INTERCEPT(pthread_rwlock_init); - TSAN_INTERCEPT(pthread_rwlock_destroy); - TSAN_INTERCEPT(pthread_rwlock_rdlock); - TSAN_INTERCEPT(pthread_rwlock_tryrdlock); - TSAN_INTERCEPT(pthread_rwlock_timedrdlock); - TSAN_INTERCEPT(pthread_rwlock_wrlock); - TSAN_INTERCEPT(pthread_rwlock_trywrlock); - TSAN_INTERCEPT(pthread_rwlock_timedwrlock); - TSAN_INTERCEPT(pthread_rwlock_unlock); - - TSAN_INTERCEPT(pthread_barrier_init); - TSAN_INTERCEPT(pthread_barrier_destroy); - TSAN_INTERCEPT(pthread_barrier_wait); - - TSAN_INTERCEPT(pthread_once); - - TSAN_INTERCEPT(fstat); - TSAN_MAYBE_INTERCEPT___FXSTAT; - TSAN_MAYBE_INTERCEPT_FSTAT64; - TSAN_MAYBE_INTERCEPT___FXSTAT64; - TSAN_INTERCEPT(open); - TSAN_MAYBE_INTERCEPT_OPEN64; - TSAN_INTERCEPT(creat); - TSAN_MAYBE_INTERCEPT_CREAT64; - TSAN_INTERCEPT(dup); - TSAN_INTERCEPT(dup2); - TSAN_INTERCEPT(dup3); - TSAN_MAYBE_INTERCEPT_EVENTFD; - TSAN_MAYBE_INTERCEPT_SIGNALFD; - TSAN_MAYBE_INTERCEPT_INOTIFY_INIT; - TSAN_MAYBE_INTERCEPT_INOTIFY_INIT1; - TSAN_INTERCEPT(socket); - TSAN_INTERCEPT(socketpair); - TSAN_INTERCEPT(connect); - TSAN_INTERCEPT(bind); - TSAN_INTERCEPT(listen); - TSAN_MAYBE_INTERCEPT_EPOLL; - TSAN_INTERCEPT(close); - TSAN_MAYBE_INTERCEPT___CLOSE; - TSAN_MAYBE_INTERCEPT___RES_ICLOSE; - TSAN_INTERCEPT(pipe); - TSAN_INTERCEPT(pipe2); - - TSAN_INTERCEPT(unlink); - TSAN_INTERCEPT(tmpfile); - TSAN_MAYBE_INTERCEPT_TMPFILE64; - TSAN_INTERCEPT(abort); - TSAN_INTERCEPT(rmdir); - TSAN_INTERCEPT(closedir); - - TSAN_INTERCEPT(sigsuspend); - TSAN_INTERCEPT(sigblock); - TSAN_INTERCEPT(sigsetmask); - TSAN_INTERCEPT(pthread_sigmask); - TSAN_INTERCEPT(raise); - TSAN_INTERCEPT(kill); - TSAN_INTERCEPT(pthread_kill); - TSAN_INTERCEPT(sleep); - TSAN_INTERCEPT(usleep); - TSAN_INTERCEPT(nanosleep); - TSAN_INTERCEPT(pause); - TSAN_INTERCEPT(gettimeofday); - TSAN_INTERCEPT(getaddrinfo); - - TSAN_INTERCEPT(fork); - TSAN_INTERCEPT(vfork); -#if !SANITIZER_ANDROID - TSAN_INTERCEPT(dl_iterate_phdr); -#endif - TSAN_MAYBE_INTERCEPT_ON_EXIT; - TSAN_INTERCEPT(__cxa_atexit); - TSAN_INTERCEPT(_exit); - -#ifdef NEED_TLS_GET_ADDR - TSAN_INTERCEPT(__tls_get_addr); -#endif - - TSAN_MAYBE_INTERCEPT__LWP_EXIT; - TSAN_MAYBE_INTERCEPT_THR_EXIT; - -#if !SANITIZER_MAC && !SANITIZER_ANDROID - // Need to setup it, because interceptors check that the function is resolved. - // But atexit is emitted directly into the module, so can't be resolved. - REAL(atexit) = (int(*)(void(*)()))unreachable; -#endif - - if (REAL(__cxa_atexit)(&finalize, 0, 0)) { - Printf("ThreadSanitizer: failed to setup atexit callback\n"); - Die(); - } - -#if !SANITIZER_MAC && !SANITIZER_NETBSD && !SANITIZER_FREEBSD - if (pthread_key_create(&interceptor_ctx()->finalize_key, &thread_finalize)) { - Printf("ThreadSanitizer: failed to create thread key\n"); - Die(); - } -#endif - - TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(cond_init); - TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(cond_signal); - TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(cond_broadcast); - TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(cond_wait); - TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(cond_destroy); - TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(mutex_init); - TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(mutex_destroy); - TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(mutex_trylock); - TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(rwlock_init); - TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(rwlock_destroy); - TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(rwlock_rdlock); - TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(rwlock_tryrdlock); - TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(rwlock_wrlock); - TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(rwlock_trywrlock); - TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(rwlock_unlock); - TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS_THR(once); - TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS_THR(sigsetmask); - - FdInit(); -} - -} // namespace __tsan - -// Invisible barrier for tests. -// There were several unsuccessful iterations for this functionality: -// 1. Initially it was implemented in user code using -// REAL(pthread_barrier_wait). But pthread_barrier_wait is not supported on -// MacOS. Futexes are linux-specific for this matter. -// 2. Then we switched to atomics+usleep(10). But usleep produced parasitic -// "as-if synchronized via sleep" messages in reports which failed some -// output tests. -// 3. Then we switched to atomics+sched_yield. But this produced tons of tsan- -// visible events, which lead to "failed to restore stack trace" failures. -// Note that no_sanitize_thread attribute does not turn off atomic interception -// so attaching it to the function defined in user code does not help. -// That's why we now have what we have. -extern "C" SANITIZER_INTERFACE_ATTRIBUTE -void __tsan_testonly_barrier_init(u64 *barrier, u32 count) { - if (count >= (1 << 8)) { - Printf("barrier_init: count is too large (%d)\n", count); - Die(); - } - // 8 lsb is thread count, the remaining are count of entered threads. - *barrier = count; -} - -extern "C" SANITIZER_INTERFACE_ATTRIBUTE -void __tsan_testonly_barrier_wait(u64 *barrier) { - unsigned old = __atomic_fetch_add(barrier, 1 << 8, __ATOMIC_RELAXED); - unsigned old_epoch = (old >> 8) / (old & 0xff); - for (;;) { - unsigned cur = __atomic_load_n(barrier, __ATOMIC_RELAXED); - unsigned cur_epoch = (cur >> 8) / (cur & 0xff); - if (cur_epoch != old_epoch) - return; - internal_sched_yield(); - } -} diff --git a/libsanitizer/tsan/tsan_interceptors_libdispatch.cpp b/libsanitizer/tsan/tsan_interceptors_libdispatch.cpp new file mode 100644 index 00000000000..5dacd3256ab --- /dev/null +++ b/libsanitizer/tsan/tsan_interceptors_libdispatch.cpp @@ -0,0 +1,782 @@ +//===-- tsan_interceptors_libdispatch.cpp ---------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of ThreadSanitizer (TSan), a race detector. +// +// Support for intercepting libdispatch (GCD). +//===----------------------------------------------------------------------===// + +#include "sanitizer_common/sanitizer_common.h" +#include "interception/interception.h" +#include "tsan_interceptors.h" +#include "tsan_rtl.h" + +#include "BlocksRuntime/Block.h" +#include "tsan_dispatch_defs.h" + +namespace __tsan { + typedef u16 uint16_t; + +typedef struct { + dispatch_queue_t queue; + void *orig_context; + dispatch_function_t orig_work; + bool free_context_in_callback; + bool submitted_synchronously; + bool is_barrier_block; + uptr non_queue_sync_object; +} block_context_t; + +// The offsets of different fields of the dispatch_queue_t structure, exported +// by libdispatch.dylib. +extern "C" struct dispatch_queue_offsets_s { + const uint16_t dqo_version; + const uint16_t dqo_label; + const uint16_t dqo_label_size; + const uint16_t dqo_flags; + const uint16_t dqo_flags_size; + const uint16_t dqo_serialnum; + const uint16_t dqo_serialnum_size; + const uint16_t dqo_width; + const uint16_t dqo_width_size; + const uint16_t dqo_running; + const uint16_t dqo_running_size; + const uint16_t dqo_suspend_cnt; + const uint16_t dqo_suspend_cnt_size; + const uint16_t dqo_target_queue; + const uint16_t dqo_target_queue_size; + const uint16_t dqo_priority; + const uint16_t dqo_priority_size; +} dispatch_queue_offsets; + +static bool IsQueueSerial(dispatch_queue_t q) { + CHECK_EQ(dispatch_queue_offsets.dqo_width_size, 2); + uptr width = *(uint16_t *)(((uptr)q) + dispatch_queue_offsets.dqo_width); + CHECK_NE(width, 0); + return width == 1; +} + +static dispatch_queue_t GetTargetQueueFromQueue(dispatch_queue_t q) { + CHECK_EQ(dispatch_queue_offsets.dqo_target_queue_size, 8); + dispatch_queue_t tq = *( + dispatch_queue_t *)(((uptr)q) + dispatch_queue_offsets.dqo_target_queue); + return tq; +} + +static dispatch_queue_t GetTargetQueueFromSource(dispatch_source_t source) { + dispatch_queue_t tq = GetTargetQueueFromQueue((dispatch_queue_t)source); + CHECK_NE(tq, 0); + return tq; +} + +static block_context_t *AllocContext(ThreadState *thr, uptr pc, + dispatch_queue_t queue, void *orig_context, + dispatch_function_t orig_work) { + block_context_t *new_context = + (block_context_t *)user_alloc_internal(thr, pc, sizeof(block_context_t)); + new_context->queue = queue; + new_context->orig_context = orig_context; + new_context->orig_work = orig_work; + new_context->free_context_in_callback = true; + new_context->submitted_synchronously = false; + new_context->is_barrier_block = false; + new_context->non_queue_sync_object = 0; + return new_context; +} + +#define GET_QUEUE_SYNC_VARS(context, q) \ + bool is_queue_serial = q && IsQueueSerial(q); \ + uptr sync_ptr = (uptr)q ?: context->non_queue_sync_object; \ + uptr serial_sync = (uptr)sync_ptr; \ + uptr concurrent_sync = sync_ptr ? ((uptr)sync_ptr) + sizeof(uptr) : 0; \ + bool serial_task = context->is_barrier_block || is_queue_serial + +static void dispatch_sync_pre_execute(ThreadState *thr, uptr pc, + block_context_t *context) { + uptr submit_sync = (uptr)context; + Acquire(thr, pc, submit_sync); + + dispatch_queue_t q = context->queue; + do { + GET_QUEUE_SYNC_VARS(context, q); + if (serial_sync) Acquire(thr, pc, serial_sync); + if (serial_task && concurrent_sync) Acquire(thr, pc, concurrent_sync); + + if (q) q = GetTargetQueueFromQueue(q); + } while (q); +} + +static void dispatch_sync_post_execute(ThreadState *thr, uptr pc, + block_context_t *context) { + uptr submit_sync = (uptr)context; + if (context->submitted_synchronously) Release(thr, pc, submit_sync); + + dispatch_queue_t q = context->queue; + do { + GET_QUEUE_SYNC_VARS(context, q); + if (serial_task && serial_sync) Release(thr, pc, serial_sync); + if (!serial_task && concurrent_sync) Release(thr, pc, concurrent_sync); + + if (q) q = GetTargetQueueFromQueue(q); + } while (q); +} + +static void dispatch_callback_wrap(void *param) { + SCOPED_INTERCEPTOR_RAW(dispatch_callback_wrap); + block_context_t *context = (block_context_t *)param; + + dispatch_sync_pre_execute(thr, pc, context); + + SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START(); + context->orig_work(context->orig_context); + SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END(); + + dispatch_sync_post_execute(thr, pc, context); + + if (context->free_context_in_callback) user_free(thr, pc, context); +} + +static void invoke_block(void *param) { + dispatch_block_t block = (dispatch_block_t)param; + block(); +} + +static void invoke_and_release_block(void *param) { + dispatch_block_t block = (dispatch_block_t)param; + block(); + Block_release(block); +} + +#define DISPATCH_INTERCEPT_ASYNC_B(name, barrier) \ + TSAN_INTERCEPTOR(void, name, dispatch_queue_t q, dispatch_block_t block) { \ + SCOPED_TSAN_INTERCEPTOR(name, q, block); \ + SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START(); \ + dispatch_block_t heap_block = Block_copy(block); \ + SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END(); \ + block_context_t *new_context = \ + AllocContext(thr, pc, q, heap_block, &invoke_and_release_block); \ + new_context->is_barrier_block = barrier; \ + Release(thr, pc, (uptr)new_context); \ + SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START(); \ + REAL(name##_f)(q, new_context, dispatch_callback_wrap); \ + SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END(); \ + } + +#define DISPATCH_INTERCEPT_SYNC_B(name, barrier) \ + TSAN_INTERCEPTOR(void, name, dispatch_queue_t q, \ + DISPATCH_NOESCAPE dispatch_block_t block) { \ + SCOPED_TSAN_INTERCEPTOR(name, q, block); \ + block_context_t new_context = { \ + q, block, &invoke_block, false, true, barrier, 0}; \ + Release(thr, pc, (uptr)&new_context); \ + SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START(); \ + REAL(name##_f)(q, &new_context, dispatch_callback_wrap); \ + SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END(); \ + Acquire(thr, pc, (uptr)&new_context); \ + } + +#define DISPATCH_INTERCEPT_ASYNC_F(name, barrier) \ + TSAN_INTERCEPTOR(void, name, dispatch_queue_t q, void *context, \ + dispatch_function_t work) { \ + SCOPED_TSAN_INTERCEPTOR(name, q, context, work); \ + block_context_t *new_context = \ + AllocContext(thr, pc, q, context, work); \ + new_context->is_barrier_block = barrier; \ + Release(thr, pc, (uptr)new_context); \ + SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START(); \ + REAL(name)(q, new_context, dispatch_callback_wrap); \ + SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END(); \ + } + +#define DISPATCH_INTERCEPT_SYNC_F(name, barrier) \ + TSAN_INTERCEPTOR(void, name, dispatch_queue_t q, void *context, \ + dispatch_function_t work) { \ + SCOPED_TSAN_INTERCEPTOR(name, q, context, work); \ + block_context_t new_context = { \ + q, context, work, false, true, barrier, 0}; \ + Release(thr, pc, (uptr)&new_context); \ + SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START(); \ + REAL(name)(q, &new_context, dispatch_callback_wrap); \ + SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END(); \ + Acquire(thr, pc, (uptr)&new_context); \ + } + +#define DISPATCH_INTERCEPT(name, barrier) \ + DISPATCH_INTERCEPT_ASYNC_F(name##_async_f, barrier) \ + DISPATCH_INTERCEPT_ASYNC_B(name##_async, barrier) \ + DISPATCH_INTERCEPT_SYNC_F(name##_sync_f, barrier) \ + DISPATCH_INTERCEPT_SYNC_B(name##_sync, barrier) + +// We wrap dispatch_async, dispatch_sync and friends where we allocate a new +// context, which is used to synchronize (we release the context before +// submitting, and the callback acquires it before executing the original +// callback). +DISPATCH_INTERCEPT(dispatch, false) +DISPATCH_INTERCEPT(dispatch_barrier, true) + +DECLARE_REAL(void, dispatch_after_f, dispatch_time_t when, + dispatch_queue_t queue, void *context, dispatch_function_t work) + +TSAN_INTERCEPTOR(void, dispatch_after, dispatch_time_t when, + dispatch_queue_t queue, dispatch_block_t block) { + SCOPED_TSAN_INTERCEPTOR(dispatch_after, when, queue, block); + SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START(); + dispatch_block_t heap_block = Block_copy(block); + SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END(); + block_context_t *new_context = + AllocContext(thr, pc, queue, heap_block, &invoke_and_release_block); + Release(thr, pc, (uptr)new_context); + SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START(); + REAL(dispatch_after_f)(when, queue, new_context, dispatch_callback_wrap); + SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END(); +} + +TSAN_INTERCEPTOR(void, dispatch_after_f, dispatch_time_t when, + dispatch_queue_t queue, void *context, + dispatch_function_t work) { + SCOPED_TSAN_INTERCEPTOR(dispatch_after_f, when, queue, context, work); + WRAP(dispatch_after)(when, queue, ^(void) { + work(context); + }); +} + +// GCD's dispatch_once implementation has a fast path that contains a racy read +// and it's inlined into user's code. Furthermore, this fast path doesn't +// establish a proper happens-before relations between the initialization and +// code following the call to dispatch_once. We could deal with this in +// instrumented code, but there's not much we can do about it in system +// libraries. Let's disable the fast path (by never storing the value ~0 to +// predicate), so the interceptor is always called, and let's add proper release +// and acquire semantics. Since TSan does not see its own atomic stores, the +// race on predicate won't be reported - the only accesses to it that TSan sees +// are the loads on the fast path. Loads don't race. Secondly, dispatch_once is +// both a macro and a real function, we want to intercept the function, so we +// need to undefine the macro. +#undef dispatch_once +TSAN_INTERCEPTOR(void, dispatch_once, dispatch_once_t *predicate, + DISPATCH_NOESCAPE dispatch_block_t block) { + SCOPED_INTERCEPTOR_RAW(dispatch_once, predicate, block); + atomic_uint32_t *a = reinterpret_cast(predicate); + u32 v = atomic_load(a, memory_order_acquire); + if (v == 0 && + atomic_compare_exchange_strong(a, &v, 1, memory_order_relaxed)) { + SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START(); + block(); + SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END(); + Release(thr, pc, (uptr)a); + atomic_store(a, 2, memory_order_release); + } else { + while (v != 2) { + internal_sched_yield(); + v = atomic_load(a, memory_order_acquire); + } + Acquire(thr, pc, (uptr)a); + } +} + +#undef dispatch_once_f +TSAN_INTERCEPTOR(void, dispatch_once_f, dispatch_once_t *predicate, + void *context, dispatch_function_t function) { + SCOPED_INTERCEPTOR_RAW(dispatch_once_f, predicate, context, function); + SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START(); + WRAP(dispatch_once)(predicate, ^(void) { + function(context); + }); + SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END(); +} + +TSAN_INTERCEPTOR(long_t, dispatch_semaphore_signal, + dispatch_semaphore_t dsema) { + SCOPED_TSAN_INTERCEPTOR(dispatch_semaphore_signal, dsema); + Release(thr, pc, (uptr)dsema); + return REAL(dispatch_semaphore_signal)(dsema); +} + +TSAN_INTERCEPTOR(long_t, dispatch_semaphore_wait, dispatch_semaphore_t dsema, + dispatch_time_t timeout) { + SCOPED_TSAN_INTERCEPTOR(dispatch_semaphore_wait, dsema, timeout); + long_t result = REAL(dispatch_semaphore_wait)(dsema, timeout); + if (result == 0) Acquire(thr, pc, (uptr)dsema); + return result; +} + +TSAN_INTERCEPTOR(long_t, dispatch_group_wait, dispatch_group_t group, + dispatch_time_t timeout) { + SCOPED_TSAN_INTERCEPTOR(dispatch_group_wait, group, timeout); + long_t result = REAL(dispatch_group_wait)(group, timeout); + if (result == 0) Acquire(thr, pc, (uptr)group); + return result; +} + +// Used, but not intercepted. +extern "C" void dispatch_group_enter(dispatch_group_t group); + +TSAN_INTERCEPTOR(void, dispatch_group_leave, dispatch_group_t group) { + SCOPED_TSAN_INTERCEPTOR(dispatch_group_leave, group); + // Acquired in the group notification callback in dispatch_group_notify[_f]. + Release(thr, pc, (uptr)group); + REAL(dispatch_group_leave)(group); +} + +TSAN_INTERCEPTOR(void, dispatch_group_async, dispatch_group_t group, + dispatch_queue_t queue, dispatch_block_t block) { + SCOPED_TSAN_INTERCEPTOR(dispatch_group_async, group, queue, block); + dispatch_retain(group); + dispatch_group_enter(group); + __block dispatch_block_t block_copy = (dispatch_block_t)Block_copy(block); + WRAP(dispatch_async)(queue, ^(void) { + block_copy(); + Block_release(block_copy); + WRAP(dispatch_group_leave)(group); + dispatch_release(group); + }); +} + +TSAN_INTERCEPTOR(void, dispatch_group_async_f, dispatch_group_t group, + dispatch_queue_t queue, void *context, + dispatch_function_t work) { + SCOPED_TSAN_INTERCEPTOR(dispatch_group_async_f, group, queue, context, work); + dispatch_retain(group); + dispatch_group_enter(group); + WRAP(dispatch_async)(queue, ^(void) { + work(context); + WRAP(dispatch_group_leave)(group); + dispatch_release(group); + }); +} + +DECLARE_REAL(void, dispatch_group_notify_f, dispatch_group_t group, + dispatch_queue_t q, void *context, dispatch_function_t work) + +TSAN_INTERCEPTOR(void, dispatch_group_notify, dispatch_group_t group, + dispatch_queue_t q, dispatch_block_t block) { + SCOPED_TSAN_INTERCEPTOR(dispatch_group_notify, group, q, block); + + // To make sure the group is still available in the callback (otherwise + // it can be already destroyed). Will be released in the callback. + dispatch_retain(group); + + SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START(); + dispatch_block_t heap_block = Block_copy(^(void) { + { + SCOPED_INTERCEPTOR_RAW(dispatch_read_callback); + // Released when leaving the group (dispatch_group_leave). + Acquire(thr, pc, (uptr)group); + } + dispatch_release(group); + block(); + }); + SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END(); + block_context_t *new_context = + AllocContext(thr, pc, q, heap_block, &invoke_and_release_block); + new_context->is_barrier_block = true; + Release(thr, pc, (uptr)new_context); + REAL(dispatch_group_notify_f)(group, q, new_context, dispatch_callback_wrap); +} + +TSAN_INTERCEPTOR(void, dispatch_group_notify_f, dispatch_group_t group, + dispatch_queue_t q, void *context, dispatch_function_t work) { + WRAP(dispatch_group_notify)(group, q, ^(void) { work(context); }); +} + +TSAN_INTERCEPTOR(void, dispatch_source_set_event_handler, + dispatch_source_t source, dispatch_block_t handler) { + SCOPED_TSAN_INTERCEPTOR(dispatch_source_set_event_handler, source, handler); + if (handler == nullptr) + return REAL(dispatch_source_set_event_handler)(source, nullptr); + dispatch_queue_t q = GetTargetQueueFromSource(source); + __block block_context_t new_context = { + q, handler, &invoke_block, false, false, false, 0 }; + dispatch_block_t new_handler = Block_copy(^(void) { + new_context.orig_context = handler; // To explicitly capture "handler". + dispatch_callback_wrap(&new_context); + }); + uptr submit_sync = (uptr)&new_context; + Release(thr, pc, submit_sync); + REAL(dispatch_source_set_event_handler)(source, new_handler); + Block_release(new_handler); +} + +TSAN_INTERCEPTOR(void, dispatch_source_set_event_handler_f, + dispatch_source_t source, dispatch_function_t handler) { + SCOPED_TSAN_INTERCEPTOR(dispatch_source_set_event_handler_f, source, handler); + if (handler == nullptr) + return REAL(dispatch_source_set_event_handler)(source, nullptr); + dispatch_block_t block = ^(void) { + handler(dispatch_get_context(source)); + }; + WRAP(dispatch_source_set_event_handler)(source, block); +} + +TSAN_INTERCEPTOR(void, dispatch_source_set_cancel_handler, + dispatch_source_t source, dispatch_block_t handler) { + SCOPED_TSAN_INTERCEPTOR(dispatch_source_set_cancel_handler, source, handler); + if (handler == nullptr) + return REAL(dispatch_source_set_cancel_handler)(source, nullptr); + dispatch_queue_t q = GetTargetQueueFromSource(source); + __block block_context_t new_context = { + q, handler, &invoke_block, false, false, false, 0}; + dispatch_block_t new_handler = Block_copy(^(void) { + new_context.orig_context = handler; // To explicitly capture "handler". + dispatch_callback_wrap(&new_context); + }); + uptr submit_sync = (uptr)&new_context; + Release(thr, pc, submit_sync); + REAL(dispatch_source_set_cancel_handler)(source, new_handler); + Block_release(new_handler); +} + +TSAN_INTERCEPTOR(void, dispatch_source_set_cancel_handler_f, + dispatch_source_t source, dispatch_function_t handler) { + SCOPED_TSAN_INTERCEPTOR(dispatch_source_set_cancel_handler_f, source, + handler); + if (handler == nullptr) + return REAL(dispatch_source_set_cancel_handler)(source, nullptr); + dispatch_block_t block = ^(void) { + handler(dispatch_get_context(source)); + }; + WRAP(dispatch_source_set_cancel_handler)(source, block); +} + +TSAN_INTERCEPTOR(void, dispatch_source_set_registration_handler, + dispatch_source_t source, dispatch_block_t handler) { + SCOPED_TSAN_INTERCEPTOR(dispatch_source_set_registration_handler, source, + handler); + if (handler == nullptr) + return REAL(dispatch_source_set_registration_handler)(source, nullptr); + dispatch_queue_t q = GetTargetQueueFromSource(source); + __block block_context_t new_context = { + q, handler, &invoke_block, false, false, false, 0}; + dispatch_block_t new_handler = Block_copy(^(void) { + new_context.orig_context = handler; // To explicitly capture "handler". + dispatch_callback_wrap(&new_context); + }); + uptr submit_sync = (uptr)&new_context; + Release(thr, pc, submit_sync); + REAL(dispatch_source_set_registration_handler)(source, new_handler); + Block_release(new_handler); +} + +TSAN_INTERCEPTOR(void, dispatch_source_set_registration_handler_f, + dispatch_source_t source, dispatch_function_t handler) { + SCOPED_TSAN_INTERCEPTOR(dispatch_source_set_registration_handler_f, source, + handler); + if (handler == nullptr) + return REAL(dispatch_source_set_registration_handler)(source, nullptr); + dispatch_block_t block = ^(void) { + handler(dispatch_get_context(source)); + }; + WRAP(dispatch_source_set_registration_handler)(source, block); +} + +TSAN_INTERCEPTOR(void, dispatch_apply, size_t iterations, + dispatch_queue_t queue, + DISPATCH_NOESCAPE void (^block)(size_t)) { + SCOPED_TSAN_INTERCEPTOR(dispatch_apply, iterations, queue, block); + + u8 sync1, sync2; + uptr parent_to_child_sync = (uptr)&sync1; + uptr child_to_parent_sync = (uptr)&sync2; + + Release(thr, pc, parent_to_child_sync); + void (^new_block)(size_t) = ^(size_t iteration) { + SCOPED_INTERCEPTOR_RAW(dispatch_apply); + Acquire(thr, pc, parent_to_child_sync); + SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START(); + block(iteration); + SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END(); + Release(thr, pc, child_to_parent_sync); + }; + SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START(); + REAL(dispatch_apply)(iterations, queue, new_block); + SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END(); + Acquire(thr, pc, child_to_parent_sync); +} + +static void invoke_block_iteration(void *param, size_t iteration) { + auto block = (void (^)(size_t)) param; + block(iteration); +} + +TSAN_INTERCEPTOR(void, dispatch_apply_f, size_t iterations, + dispatch_queue_t queue, void *context, + void (*work)(void *, size_t)) { + SCOPED_TSAN_INTERCEPTOR(dispatch_apply_f, iterations, queue, context, work); + + // Unfortunately, we cannot delegate to dispatch_apply, since libdispatch + // implements dispatch_apply in terms of dispatch_apply_f. + u8 sync1, sync2; + uptr parent_to_child_sync = (uptr)&sync1; + uptr child_to_parent_sync = (uptr)&sync2; + + Release(thr, pc, parent_to_child_sync); + void (^new_block)(size_t) = ^(size_t iteration) { + SCOPED_INTERCEPTOR_RAW(dispatch_apply_f); + Acquire(thr, pc, parent_to_child_sync); + SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START(); + work(context, iteration); + SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END(); + Release(thr, pc, child_to_parent_sync); + }; + SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START(); + REAL(dispatch_apply_f)(iterations, queue, new_block, invoke_block_iteration); + SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END(); + Acquire(thr, pc, child_to_parent_sync); +} + +DECLARE_REAL_AND_INTERCEPTOR(void, free, void *ptr) +DECLARE_REAL_AND_INTERCEPTOR(int, munmap, void *addr, long_t sz) + +TSAN_INTERCEPTOR(dispatch_data_t, dispatch_data_create, const void *buffer, + size_t size, dispatch_queue_t q, dispatch_block_t destructor) { + SCOPED_TSAN_INTERCEPTOR(dispatch_data_create, buffer, size, q, destructor); + if ((q == nullptr) || (destructor == DISPATCH_DATA_DESTRUCTOR_DEFAULT)) + return REAL(dispatch_data_create)(buffer, size, q, destructor); + + if (destructor == DISPATCH_DATA_DESTRUCTOR_FREE) + destructor = ^(void) { WRAP(free)((void *)(uintptr_t)buffer); }; + else if (destructor == DISPATCH_DATA_DESTRUCTOR_MUNMAP) + destructor = ^(void) { WRAP(munmap)((void *)(uintptr_t)buffer, size); }; + + SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START(); + dispatch_block_t heap_block = Block_copy(destructor); + SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END(); + block_context_t *new_context = + AllocContext(thr, pc, q, heap_block, &invoke_and_release_block); + uptr submit_sync = (uptr)new_context; + Release(thr, pc, submit_sync); + return REAL(dispatch_data_create)(buffer, size, q, ^(void) { + dispatch_callback_wrap(new_context); + }); +} + +typedef void (^fd_handler_t)(dispatch_data_t data, int error); +typedef void (^cleanup_handler_t)(int error); + +TSAN_INTERCEPTOR(void, dispatch_read, dispatch_fd_t fd, size_t length, + dispatch_queue_t q, fd_handler_t h) { + SCOPED_TSAN_INTERCEPTOR(dispatch_read, fd, length, q, h); + __block block_context_t new_context = { + q, nullptr, &invoke_block, false, false, false, 0}; + fd_handler_t new_h = Block_copy(^(dispatch_data_t data, int error) { + new_context.orig_context = ^(void) { + h(data, error); + }; + dispatch_callback_wrap(&new_context); + }); + uptr submit_sync = (uptr)&new_context; + Release(thr, pc, submit_sync); + REAL(dispatch_read)(fd, length, q, new_h); + Block_release(new_h); +} + +TSAN_INTERCEPTOR(void, dispatch_write, dispatch_fd_t fd, dispatch_data_t data, + dispatch_queue_t q, fd_handler_t h) { + SCOPED_TSAN_INTERCEPTOR(dispatch_write, fd, data, q, h); + __block block_context_t new_context = { + q, nullptr, &invoke_block, false, false, false, 0}; + fd_handler_t new_h = Block_copy(^(dispatch_data_t data, int error) { + new_context.orig_context = ^(void) { + h(data, error); + }; + dispatch_callback_wrap(&new_context); + }); + uptr submit_sync = (uptr)&new_context; + Release(thr, pc, submit_sync); + REAL(dispatch_write)(fd, data, q, new_h); + Block_release(new_h); +} + +TSAN_INTERCEPTOR(void, dispatch_io_read, dispatch_io_t channel, off_t offset, + size_t length, dispatch_queue_t q, dispatch_io_handler_t h) { + SCOPED_TSAN_INTERCEPTOR(dispatch_io_read, channel, offset, length, q, h); + __block block_context_t new_context = { + q, nullptr, &invoke_block, false, false, false, 0}; + dispatch_io_handler_t new_h = + Block_copy(^(bool done, dispatch_data_t data, int error) { + new_context.orig_context = ^(void) { + h(done, data, error); + }; + dispatch_callback_wrap(&new_context); + }); + uptr submit_sync = (uptr)&new_context; + Release(thr, pc, submit_sync); + REAL(dispatch_io_read)(channel, offset, length, q, new_h); + Block_release(new_h); +} + +TSAN_INTERCEPTOR(void, dispatch_io_write, dispatch_io_t channel, off_t offset, + dispatch_data_t data, dispatch_queue_t q, + dispatch_io_handler_t h) { + SCOPED_TSAN_INTERCEPTOR(dispatch_io_write, channel, offset, data, q, h); + __block block_context_t new_context = { + q, nullptr, &invoke_block, false, false, false, 0}; + dispatch_io_handler_t new_h = + Block_copy(^(bool done, dispatch_data_t data, int error) { + new_context.orig_context = ^(void) { + h(done, data, error); + }; + dispatch_callback_wrap(&new_context); + }); + uptr submit_sync = (uptr)&new_context; + Release(thr, pc, submit_sync); + REAL(dispatch_io_write)(channel, offset, data, q, new_h); + Block_release(new_h); +} + +TSAN_INTERCEPTOR(void, dispatch_io_barrier, dispatch_io_t channel, + dispatch_block_t barrier) { + SCOPED_TSAN_INTERCEPTOR(dispatch_io_barrier, channel, barrier); + __block block_context_t new_context = { + nullptr, nullptr, &invoke_block, false, false, false, 0}; + new_context.non_queue_sync_object = (uptr)channel; + new_context.is_barrier_block = true; + dispatch_block_t new_block = Block_copy(^(void) { + new_context.orig_context = ^(void) { + barrier(); + }; + dispatch_callback_wrap(&new_context); + }); + uptr submit_sync = (uptr)&new_context; + Release(thr, pc, submit_sync); + REAL(dispatch_io_barrier)(channel, new_block); + Block_release(new_block); +} + +TSAN_INTERCEPTOR(dispatch_io_t, dispatch_io_create, dispatch_io_type_t type, + dispatch_fd_t fd, dispatch_queue_t q, cleanup_handler_t h) { + SCOPED_TSAN_INTERCEPTOR(dispatch_io_create, type, fd, q, h); + __block dispatch_io_t new_channel = nullptr; + __block block_context_t new_context = { + q, nullptr, &invoke_block, false, false, false, 0}; + cleanup_handler_t new_h = Block_copy(^(int error) { + { + SCOPED_INTERCEPTOR_RAW(dispatch_io_create_callback); + Acquire(thr, pc, (uptr)new_channel); // Release() in dispatch_io_close. + } + new_context.orig_context = ^(void) { + h(error); + }; + dispatch_callback_wrap(&new_context); + }); + uptr submit_sync = (uptr)&new_context; + Release(thr, pc, submit_sync); + new_channel = REAL(dispatch_io_create)(type, fd, q, new_h); + Block_release(new_h); + return new_channel; +} + +TSAN_INTERCEPTOR(dispatch_io_t, dispatch_io_create_with_path, + dispatch_io_type_t type, const char *path, int oflag, + mode_t mode, dispatch_queue_t q, cleanup_handler_t h) { + SCOPED_TSAN_INTERCEPTOR(dispatch_io_create_with_path, type, path, oflag, mode, + q, h); + __block dispatch_io_t new_channel = nullptr; + __block block_context_t new_context = { + q, nullptr, &invoke_block, false, false, false, 0}; + cleanup_handler_t new_h = Block_copy(^(int error) { + { + SCOPED_INTERCEPTOR_RAW(dispatch_io_create_callback); + Acquire(thr, pc, (uptr)new_channel); // Release() in dispatch_io_close. + } + new_context.orig_context = ^(void) { + h(error); + }; + dispatch_callback_wrap(&new_context); + }); + uptr submit_sync = (uptr)&new_context; + Release(thr, pc, submit_sync); + new_channel = + REAL(dispatch_io_create_with_path)(type, path, oflag, mode, q, new_h); + Block_release(new_h); + return new_channel; +} + +TSAN_INTERCEPTOR(dispatch_io_t, dispatch_io_create_with_io, + dispatch_io_type_t type, dispatch_io_t io, dispatch_queue_t q, + cleanup_handler_t h) { + SCOPED_TSAN_INTERCEPTOR(dispatch_io_create_with_io, type, io, q, h); + __block dispatch_io_t new_channel = nullptr; + __block block_context_t new_context = { + q, nullptr, &invoke_block, false, false, false, 0}; + cleanup_handler_t new_h = Block_copy(^(int error) { + { + SCOPED_INTERCEPTOR_RAW(dispatch_io_create_callback); + Acquire(thr, pc, (uptr)new_channel); // Release() in dispatch_io_close. + } + new_context.orig_context = ^(void) { + h(error); + }; + dispatch_callback_wrap(&new_context); + }); + uptr submit_sync = (uptr)&new_context; + Release(thr, pc, submit_sync); + new_channel = REAL(dispatch_io_create_with_io)(type, io, q, new_h); + Block_release(new_h); + return new_channel; +} + +TSAN_INTERCEPTOR(void, dispatch_io_close, dispatch_io_t channel, + dispatch_io_close_flags_t flags) { + SCOPED_TSAN_INTERCEPTOR(dispatch_io_close, channel, flags); + Release(thr, pc, (uptr)channel); // Acquire() in dispatch_io_create[_*]. + return REAL(dispatch_io_close)(channel, flags); +} + +// Resuming a suspended queue needs to synchronize with all subsequent +// executions of blocks in that queue. +TSAN_INTERCEPTOR(void, dispatch_resume, dispatch_object_t o) { + SCOPED_TSAN_INTERCEPTOR(dispatch_resume, o); + Release(thr, pc, (uptr)o); // Synchronizes with the Acquire() on serial_sync + // in dispatch_sync_pre_execute + return REAL(dispatch_resume)(o); +} + +void InitializeLibdispatchInterceptors() { + INTERCEPT_FUNCTION(dispatch_async); + INTERCEPT_FUNCTION(dispatch_async_f); + INTERCEPT_FUNCTION(dispatch_sync); + INTERCEPT_FUNCTION(dispatch_sync_f); + INTERCEPT_FUNCTION(dispatch_barrier_async); + INTERCEPT_FUNCTION(dispatch_barrier_async_f); + INTERCEPT_FUNCTION(dispatch_barrier_sync); + INTERCEPT_FUNCTION(dispatch_barrier_sync_f); + INTERCEPT_FUNCTION(dispatch_after); + INTERCEPT_FUNCTION(dispatch_after_f); + INTERCEPT_FUNCTION(dispatch_once); + INTERCEPT_FUNCTION(dispatch_once_f); + INTERCEPT_FUNCTION(dispatch_semaphore_signal); + INTERCEPT_FUNCTION(dispatch_semaphore_wait); + INTERCEPT_FUNCTION(dispatch_group_wait); + INTERCEPT_FUNCTION(dispatch_group_leave); + INTERCEPT_FUNCTION(dispatch_group_async); + INTERCEPT_FUNCTION(dispatch_group_async_f); + INTERCEPT_FUNCTION(dispatch_group_notify); + INTERCEPT_FUNCTION(dispatch_group_notify_f); + INTERCEPT_FUNCTION(dispatch_source_set_event_handler); + INTERCEPT_FUNCTION(dispatch_source_set_event_handler_f); + INTERCEPT_FUNCTION(dispatch_source_set_cancel_handler); + INTERCEPT_FUNCTION(dispatch_source_set_cancel_handler_f); + INTERCEPT_FUNCTION(dispatch_source_set_registration_handler); + INTERCEPT_FUNCTION(dispatch_source_set_registration_handler_f); + INTERCEPT_FUNCTION(dispatch_apply); + INTERCEPT_FUNCTION(dispatch_apply_f); + INTERCEPT_FUNCTION(dispatch_data_create); + INTERCEPT_FUNCTION(dispatch_read); + INTERCEPT_FUNCTION(dispatch_write); + INTERCEPT_FUNCTION(dispatch_io_read); + INTERCEPT_FUNCTION(dispatch_io_write); + INTERCEPT_FUNCTION(dispatch_io_barrier); + INTERCEPT_FUNCTION(dispatch_io_create); + INTERCEPT_FUNCTION(dispatch_io_create_with_path); + INTERCEPT_FUNCTION(dispatch_io_create_with_io); + INTERCEPT_FUNCTION(dispatch_io_close); + INTERCEPT_FUNCTION(dispatch_resume); +} + +} // namespace __tsan diff --git a/libsanitizer/tsan/tsan_interceptors_mac.cpp b/libsanitizer/tsan/tsan_interceptors_mac.cpp index c2083f8cde9..aa29536d861 100644 --- a/libsanitizer/tsan/tsan_interceptors_mac.cpp +++ b/libsanitizer/tsan/tsan_interceptors_mac.cpp @@ -23,13 +23,14 @@ #include #include #include +#include #include #if defined(__has_include) && __has_include() #include #endif // #if defined(__has_include) && __has_include() -typedef long long_t; // NOLINT +typedef long long_t; extern "C" { int getcontext(ucontext_t *ucp) __attribute__((returns_twice)); @@ -246,6 +247,45 @@ TSAN_INTERCEPTOR(void, os_lock_unlock, void *lock) { REAL(os_lock_unlock)(lock); } +TSAN_INTERCEPTOR(void, os_unfair_lock_lock, os_unfair_lock_t lock) { + if (!cur_thread()->is_inited || cur_thread()->is_dead) { + return REAL(os_unfair_lock_lock)(lock); + } + SCOPED_TSAN_INTERCEPTOR(os_unfair_lock_lock, lock); + REAL(os_unfair_lock_lock)(lock); + Acquire(thr, pc, (uptr)lock); +} + +TSAN_INTERCEPTOR(void, os_unfair_lock_lock_with_options, os_unfair_lock_t lock, + u32 options) { + if (!cur_thread()->is_inited || cur_thread()->is_dead) { + return REAL(os_unfair_lock_lock_with_options)(lock, options); + } + SCOPED_TSAN_INTERCEPTOR(os_unfair_lock_lock_with_options, lock, options); + REAL(os_unfair_lock_lock_with_options)(lock, options); + Acquire(thr, pc, (uptr)lock); +} + +TSAN_INTERCEPTOR(bool, os_unfair_lock_trylock, os_unfair_lock_t lock) { + if (!cur_thread()->is_inited || cur_thread()->is_dead) { + return REAL(os_unfair_lock_trylock)(lock); + } + SCOPED_TSAN_INTERCEPTOR(os_unfair_lock_trylock, lock); + bool result = REAL(os_unfair_lock_trylock)(lock); + if (result) + Acquire(thr, pc, (uptr)lock); + return result; +} + +TSAN_INTERCEPTOR(void, os_unfair_lock_unlock, os_unfair_lock_t lock) { + if (!cur_thread()->is_inited || cur_thread()->is_dead) { + return REAL(os_unfair_lock_unlock)(lock); + } + SCOPED_TSAN_INTERCEPTOR(os_unfair_lock_unlock, lock); + Release(thr, pc, (uptr)lock); + REAL(os_unfair_lock_unlock)(lock); +} + #if defined(__has_include) && __has_include() TSAN_INTERCEPTOR(void, xpc_connection_set_event_handler, diff --git a/libsanitizer/tsan/tsan_interceptors_mach_vm.cpp b/libsanitizer/tsan/tsan_interceptors_mach_vm.cpp new file mode 100644 index 00000000000..cd318f8af93 --- /dev/null +++ b/libsanitizer/tsan/tsan_interceptors_mach_vm.cpp @@ -0,0 +1,52 @@ +//===-- tsan_interceptors_mach_vm.cpp -------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of ThreadSanitizer (TSan), a race detector. +// +// Interceptors for mach_vm_* user space memory routines on Darwin. +//===----------------------------------------------------------------------===// + +#include "interception/interception.h" +#include "tsan_interceptors.h" +#include "tsan_platform.h" + +#include + +namespace __tsan { + +static bool intersects_with_shadow(mach_vm_address_t *address, + mach_vm_size_t size, int flags) { + // VM_FLAGS_FIXED is 0x0, so we have to test for VM_FLAGS_ANYWHERE. + if (flags & VM_FLAGS_ANYWHERE) return false; + uptr ptr = *address; + return !IsAppMem(ptr) || !IsAppMem(ptr + size - 1); +} + +TSAN_INTERCEPTOR(kern_return_t, mach_vm_allocate, vm_map_t target, + mach_vm_address_t *address, mach_vm_size_t size, int flags) { + SCOPED_TSAN_INTERCEPTOR(mach_vm_allocate, target, address, size, flags); + if (target != mach_task_self()) + return REAL(mach_vm_allocate)(target, address, size, flags); + if (intersects_with_shadow(address, size, flags)) + return KERN_NO_SPACE; + kern_return_t res = REAL(mach_vm_allocate)(target, address, size, flags); + if (res == KERN_SUCCESS) + MemoryRangeImitateWriteOrResetRange(thr, pc, *address, size); + return res; +} + +TSAN_INTERCEPTOR(kern_return_t, mach_vm_deallocate, vm_map_t target, + mach_vm_address_t address, mach_vm_size_t size) { + SCOPED_TSAN_INTERCEPTOR(mach_vm_deallocate, target, address, size); + if (target != mach_task_self()) + return REAL(mach_vm_deallocate)(target, address, size); + UnmapShadow(thr, address, size); + return REAL(mach_vm_deallocate)(target, address, size); +} + +} // namespace __tsan diff --git a/libsanitizer/tsan/tsan_interceptors_posix.cpp b/libsanitizer/tsan/tsan_interceptors_posix.cpp new file mode 100644 index 00000000000..8aea1e4ec05 --- /dev/null +++ b/libsanitizer/tsan/tsan_interceptors_posix.cpp @@ -0,0 +1,2850 @@ +//===-- tsan_interceptors_posix.cpp ---------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of ThreadSanitizer (TSan), a race detector. +// +// FIXME: move as many interceptors as possible into +// sanitizer_common/sanitizer_common_interceptors.inc +//===----------------------------------------------------------------------===// + +#include "sanitizer_common/sanitizer_atomic.h" +#include "sanitizer_common/sanitizer_errno.h" +#include "sanitizer_common/sanitizer_libc.h" +#include "sanitizer_common/sanitizer_linux.h" +#include "sanitizer_common/sanitizer_platform_limits_netbsd.h" +#include "sanitizer_common/sanitizer_platform_limits_posix.h" +#include "sanitizer_common/sanitizer_placement_new.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 "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" + +using namespace __tsan; + +#if SANITIZER_FREEBSD || SANITIZER_MAC +#define stdout __stdoutp +#define stderr __stderrp +#endif + +#if SANITIZER_NETBSD +#define dirfd(dirp) (*(int *)(dirp)) +#define fileno_unlocked(fp) \ + (((__sanitizer_FILE *)fp)->_file == -1 \ + ? -1 \ + : (int)(unsigned short)(((__sanitizer_FILE *)fp)->_file)) + +#define stdout ((__sanitizer_FILE*)&__sF[1]) +#define stderr ((__sanitizer_FILE*)&__sF[2]) + +#define nanosleep __nanosleep50 +#define vfork __vfork14 +#endif + +#if SANITIZER_ANDROID +#define mallopt(a, b) +#endif + +#ifdef __mips__ +const int kSigCount = 129; +#else +const int kSigCount = 65; +#endif + +#ifdef __mips__ +struct ucontext_t { + u64 opaque[768 / sizeof(u64) + 1]; +}; +#else +struct ucontext_t { + // The size is determined by looking at sizeof of real ucontext_t on linux. + u64 opaque[936 / sizeof(u64) + 1]; +}; +#endif + +#if defined(__x86_64__) || defined(__mips__) || SANITIZER_PPC64V1 +#define PTHREAD_ABI_BASE "GLIBC_2.3.2" +#elif defined(__aarch64__) || SANITIZER_PPC64V2 +#define PTHREAD_ABI_BASE "GLIBC_2.17" +#endif + +extern "C" int pthread_attr_init(void *attr); +extern "C" int pthread_attr_destroy(void *attr); +DECLARE_REAL(int, pthread_attr_getdetachstate, void *, void *) +extern "C" int pthread_attr_setstacksize(void *attr, uptr stacksize); +extern "C" int pthread_key_create(unsigned *key, void (*destructor)(void* v)); +extern "C" int pthread_setspecific(unsigned key, const void *v); +DECLARE_REAL(int, pthread_mutexattr_gettype, void *, void *) +DECLARE_REAL(int, fflush, __sanitizer_FILE *fp) +DECLARE_REAL_AND_INTERCEPTOR(void *, malloc, uptr size) +DECLARE_REAL_AND_INTERCEPTOR(void, free, void *ptr) +extern "C" void *pthread_self(); +extern "C" void _exit(int status); +#if !SANITIZER_NETBSD +extern "C" int fileno_unlocked(void *stream); +extern "C" int dirfd(void *dirp); +#endif +#if !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_NETBSD +extern "C" int mallopt(int param, int value); +#endif +#if SANITIZER_NETBSD +extern __sanitizer_FILE __sF[]; +#else +extern __sanitizer_FILE *stdout, *stderr; +#endif +#if !SANITIZER_FREEBSD && !SANITIZER_MAC && !SANITIZER_NETBSD +const int PTHREAD_MUTEX_RECURSIVE = 1; +const int PTHREAD_MUTEX_RECURSIVE_NP = 1; +#else +const int PTHREAD_MUTEX_RECURSIVE = 2; +const int PTHREAD_MUTEX_RECURSIVE_NP = 2; +#endif +#if !SANITIZER_FREEBSD && !SANITIZER_MAC && !SANITIZER_NETBSD +const int EPOLL_CTL_ADD = 1; +#endif +const int SIGILL = 4; +const int SIGTRAP = 5; +const int SIGABRT = 6; +const int SIGFPE = 8; +const int SIGSEGV = 11; +const int SIGPIPE = 13; +const int SIGTERM = 15; +#if defined(__mips__) || SANITIZER_FREEBSD || SANITIZER_MAC || SANITIZER_NETBSD +const int SIGBUS = 10; +const int SIGSYS = 12; +#else +const int SIGBUS = 7; +const int SIGSYS = 31; +#endif +void *const MAP_FAILED = (void*)-1; +#if SANITIZER_NETBSD +const int PTHREAD_BARRIER_SERIAL_THREAD = 1234567; +#elif !SANITIZER_MAC +const int PTHREAD_BARRIER_SERIAL_THREAD = -1; +#endif +const int MAP_FIXED = 0x10; +typedef long long_t; + +// From /usr/include/unistd.h +# define F_ULOCK 0 /* Unlock a previously locked region. */ +# define F_LOCK 1 /* Lock a region for exclusive use. */ +# define F_TLOCK 2 /* Test and lock a region for exclusive use. */ +# define F_TEST 3 /* Test a region for other processes locks. */ + +#if SANITIZER_FREEBSD || SANITIZER_MAC || SANITIZER_NETBSD +const int SA_SIGINFO = 0x40; +const int SIG_SETMASK = 3; +#elif defined(__mips__) +const int SA_SIGINFO = 8; +const int SIG_SETMASK = 3; +#else +const int SA_SIGINFO = 4; +const int SIG_SETMASK = 2; +#endif + +#define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED \ + (cur_thread_init(), !cur_thread()->is_inited) + +namespace __tsan { +struct SignalDesc { + bool armed; + bool sigaction; + __sanitizer_siginfo siginfo; + ucontext_t ctx; +}; + +struct ThreadSignalContext { + int int_signal_send; + atomic_uintptr_t in_blocking_func; + atomic_uintptr_t have_pending_signals; + SignalDesc pending_signals[kSigCount]; + // emptyset and oldset are too big for stack. + __sanitizer_sigset_t emptyset; + __sanitizer_sigset_t oldset; +}; + +// The sole reason tsan wraps atexit callbacks is to establish synchronization +// between callback setup and callback execution. +struct AtExitCtx { + void (*f)(); + void *arg; +}; + +// InterceptorContext holds all global data required for interceptors. +// It's explicitly constructed in InitializeInterceptors with placement new +// and is never destroyed. This allows usage of members with non-trivial +// constructors and destructors. +struct InterceptorContext { + // The object is 64-byte aligned, because we want hot data to be located + // in a single cache line if possible (it's accessed in every interceptor). + ALIGNED(64) LibIgnore libignore; + __sanitizer_sigaction sigactions[kSigCount]; +#if !SANITIZER_MAC && !SANITIZER_NETBSD + unsigned finalize_key; +#endif + + BlockingMutex atexit_mu; + Vector AtExitStack; + + InterceptorContext() + : libignore(LINKER_INITIALIZED), AtExitStack() { + } +}; + +static ALIGNED(64) char interceptor_placeholder[sizeof(InterceptorContext)]; +InterceptorContext *interceptor_ctx() { + return reinterpret_cast(&interceptor_placeholder[0]); +} + +LibIgnore *libignore() { + return &interceptor_ctx()->libignore; +} + +void InitializeLibIgnore() { + const SuppressionContext &supp = *Suppressions(); + const uptr n = supp.SuppressionCount(); + for (uptr i = 0; i < n; i++) { + const Suppression *s = supp.SuppressionAt(i); + if (0 == internal_strcmp(s->type, kSuppressionLib)) + libignore()->AddIgnoredLibrary(s->templ); + } + if (flags()->ignore_noninstrumented_modules) + libignore()->IgnoreNoninstrumentedModules(true); + libignore()->OnLibraryLoaded(0); +} + +// The following two hooks can be used by for cooperative scheduling when +// locking. +#ifdef TSAN_EXTERNAL_HOOKS +void OnPotentiallyBlockingRegionBegin(); +void OnPotentiallyBlockingRegionEnd(); +#else +SANITIZER_WEAK_CXX_DEFAULT_IMPL void OnPotentiallyBlockingRegionBegin() {} +SANITIZER_WEAK_CXX_DEFAULT_IMPL void OnPotentiallyBlockingRegionEnd() {} +#endif + +} // namespace __tsan + +static ThreadSignalContext *SigCtx(ThreadState *thr) { + ThreadSignalContext *ctx = (ThreadSignalContext*)thr->signal_ctx; + if (ctx == 0 && !thr->is_dead) { + ctx = (ThreadSignalContext*)MmapOrDie(sizeof(*ctx), "ThreadSignalContext"); + MemoryResetRange(thr, (uptr)&SigCtx, (uptr)ctx, sizeof(*ctx)); + thr->signal_ctx = ctx; + } + return ctx; +} + +ScopedInterceptor::ScopedInterceptor(ThreadState *thr, const char *fname, + uptr pc) + : thr_(thr), pc_(pc), in_ignored_lib_(false), ignoring_(false) { + Initialize(thr); + if (!thr_->is_inited) return; + if (!thr_->ignore_interceptors) FuncEntry(thr, pc); + DPrintf("#%d: intercept %s()\n", thr_->tid, fname); + ignoring_ = + !thr_->in_ignored_lib && libignore()->IsIgnored(pc, &in_ignored_lib_); + EnableIgnores(); +} + +ScopedInterceptor::~ScopedInterceptor() { + if (!thr_->is_inited) return; + DisableIgnores(); + if (!thr_->ignore_interceptors) { + ProcessPendingSignals(thr_); + FuncExit(thr_); + CheckNoLocks(thr_); + } +} + +void ScopedInterceptor::EnableIgnores() { + if (ignoring_) { + ThreadIgnoreBegin(thr_, pc_, /*save_stack=*/false); + if (flags()->ignore_noninstrumented_modules) thr_->suppress_reports++; + if (in_ignored_lib_) { + DCHECK(!thr_->in_ignored_lib); + thr_->in_ignored_lib = true; + } + } +} + +void ScopedInterceptor::DisableIgnores() { + if (ignoring_) { + ThreadIgnoreEnd(thr_, pc_); + if (flags()->ignore_noninstrumented_modules) thr_->suppress_reports--; + if (in_ignored_lib_) { + DCHECK(thr_->in_ignored_lib); + thr_->in_ignored_lib = false; + } + } +} + +#define TSAN_INTERCEPT(func) INTERCEPT_FUNCTION(func) +#if SANITIZER_FREEBSD +# define TSAN_INTERCEPT_VER(func, ver) INTERCEPT_FUNCTION(func) +# define TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(func) +# define TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS_THR(func) +#elif SANITIZER_NETBSD +# define TSAN_INTERCEPT_VER(func, ver) INTERCEPT_FUNCTION(func) +# define TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(func) \ + INTERCEPT_FUNCTION(__libc_##func) +# define TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS_THR(func) \ + INTERCEPT_FUNCTION(__libc_thr_##func) +#else +# define TSAN_INTERCEPT_VER(func, ver) INTERCEPT_FUNCTION_VER(func, ver) +# define TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(func) +# define TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS_THR(func) +#endif + +#define READ_STRING_OF_LEN(thr, pc, s, len, n) \ + MemoryAccessRange((thr), (pc), (uptr)(s), \ + common_flags()->strict_string_checks ? (len) + 1 : (n), false) + +#define READ_STRING(thr, pc, s, n) \ + READ_STRING_OF_LEN((thr), (pc), (s), internal_strlen(s), (n)) + +#define BLOCK_REAL(name) (BlockingCall(thr), REAL(name)) + +struct BlockingCall { + explicit BlockingCall(ThreadState *thr) + : thr(thr) + , ctx(SigCtx(thr)) { + for (;;) { + atomic_store(&ctx->in_blocking_func, 1, memory_order_relaxed); + if (atomic_load(&ctx->have_pending_signals, memory_order_relaxed) == 0) + break; + atomic_store(&ctx->in_blocking_func, 0, memory_order_relaxed); + ProcessPendingSignals(thr); + } + // When we are in a "blocking call", we process signals asynchronously + // (right when they arrive). In this context we do not expect to be + // executing any user/runtime code. The known interceptor sequence when + // this is not true is: pthread_join -> munmap(stack). It's fine + // to ignore munmap in this case -- we handle stack shadow separately. + thr->ignore_interceptors++; + } + + ~BlockingCall() { + thr->ignore_interceptors--; + atomic_store(&ctx->in_blocking_func, 0, memory_order_relaxed); + } + + ThreadState *thr; + ThreadSignalContext *ctx; +}; + +TSAN_INTERCEPTOR(unsigned, sleep, unsigned sec) { + SCOPED_TSAN_INTERCEPTOR(sleep, sec); + unsigned res = BLOCK_REAL(sleep)(sec); + AfterSleep(thr, pc); + return res; +} + +TSAN_INTERCEPTOR(int, usleep, long_t usec) { + SCOPED_TSAN_INTERCEPTOR(usleep, usec); + int res = BLOCK_REAL(usleep)(usec); + AfterSleep(thr, pc); + return res; +} + +TSAN_INTERCEPTOR(int, nanosleep, void *req, void *rem) { + SCOPED_TSAN_INTERCEPTOR(nanosleep, req, rem); + int res = BLOCK_REAL(nanosleep)(req, rem); + AfterSleep(thr, pc); + return res; +} + +TSAN_INTERCEPTOR(int, pause, int fake) { + SCOPED_TSAN_INTERCEPTOR(pause, fake); + return BLOCK_REAL(pause)(fake); +} + +static void at_exit_wrapper() { + AtExitCtx *ctx; + { + // Ensure thread-safety. + BlockingMutexLock l(&interceptor_ctx()->atexit_mu); + + // Pop AtExitCtx from the top of the stack of callback functions + uptr element = interceptor_ctx()->AtExitStack.Size() - 1; + ctx = interceptor_ctx()->AtExitStack[element]; + interceptor_ctx()->AtExitStack.PopBack(); + } + + Acquire(cur_thread(), (uptr)0, (uptr)ctx); + ((void(*)())ctx->f)(); + InternalFree(ctx); +} + +static void cxa_at_exit_wrapper(void *arg) { + Acquire(cur_thread(), 0, (uptr)arg); + AtExitCtx *ctx = (AtExitCtx*)arg; + ((void(*)(void *arg))ctx->f)(ctx->arg); + InternalFree(ctx); +} + +static int setup_at_exit_wrapper(ThreadState *thr, uptr pc, void(*f)(), + void *arg, void *dso); + +#if !SANITIZER_ANDROID +TSAN_INTERCEPTOR(int, atexit, void (*f)()) { + if (in_symbolizer()) + return 0; + // We want to setup the atexit callback even if we are in ignored lib + // or after fork. + SCOPED_INTERCEPTOR_RAW(atexit, f); + return setup_at_exit_wrapper(thr, pc, (void(*)())f, 0, 0); +} +#endif + +TSAN_INTERCEPTOR(int, __cxa_atexit, void (*f)(void *a), void *arg, void *dso) { + if (in_symbolizer()) + return 0; + SCOPED_TSAN_INTERCEPTOR(__cxa_atexit, f, arg, dso); + return setup_at_exit_wrapper(thr, pc, (void(*)())f, arg, dso); +} + +static int setup_at_exit_wrapper(ThreadState *thr, uptr pc, void(*f)(), + void *arg, void *dso) { + AtExitCtx *ctx = (AtExitCtx*)InternalAlloc(sizeof(AtExitCtx)); + ctx->f = f; + ctx->arg = arg; + Release(thr, pc, (uptr)ctx); + // Memory allocation in __cxa_atexit will race with free during exit, + // because we do not see synchronization around atexit callback list. + ThreadIgnoreBegin(thr, pc); + int res; + if (!dso) { + // NetBSD does not preserve the 2nd argument if dso is equal to 0 + // Store ctx in a local stack-like structure + + // Ensure thread-safety. + BlockingMutexLock l(&interceptor_ctx()->atexit_mu); + + res = REAL(__cxa_atexit)((void (*)(void *a))at_exit_wrapper, 0, 0); + // Push AtExitCtx on the top of the stack of callback functions + if (!res) { + interceptor_ctx()->AtExitStack.PushBack(ctx); + } + } else { + res = REAL(__cxa_atexit)(cxa_at_exit_wrapper, ctx, dso); + } + ThreadIgnoreEnd(thr, pc); + return res; +} + +#if !SANITIZER_MAC && !SANITIZER_NETBSD +static void on_exit_wrapper(int status, void *arg) { + ThreadState *thr = cur_thread(); + uptr pc = 0; + Acquire(thr, pc, (uptr)arg); + AtExitCtx *ctx = (AtExitCtx*)arg; + ((void(*)(int status, void *arg))ctx->f)(status, ctx->arg); + InternalFree(ctx); +} + +TSAN_INTERCEPTOR(int, on_exit, void(*f)(int, void*), void *arg) { + if (in_symbolizer()) + return 0; + SCOPED_TSAN_INTERCEPTOR(on_exit, f, arg); + AtExitCtx *ctx = (AtExitCtx*)InternalAlloc(sizeof(AtExitCtx)); + ctx->f = (void(*)())f; + ctx->arg = arg; + Release(thr, pc, (uptr)ctx); + // Memory allocation in __cxa_atexit will race with free during exit, + // because we do not see synchronization around atexit callback list. + ThreadIgnoreBegin(thr, pc); + int res = REAL(on_exit)(on_exit_wrapper, ctx); + ThreadIgnoreEnd(thr, pc); + return res; +} +#define TSAN_MAYBE_INTERCEPT_ON_EXIT TSAN_INTERCEPT(on_exit) +#else +#define TSAN_MAYBE_INTERCEPT_ON_EXIT +#endif + +// Cleanup old bufs. +static void JmpBufGarbageCollect(ThreadState *thr, uptr sp) { + for (uptr i = 0; i < thr->jmp_bufs.Size(); i++) { + JmpBuf *buf = &thr->jmp_bufs[i]; + if (buf->sp <= sp) { + uptr sz = thr->jmp_bufs.Size(); + internal_memcpy(buf, &thr->jmp_bufs[sz - 1], sizeof(*buf)); + thr->jmp_bufs.PopBack(); + i--; + } + } +} + +static void SetJmp(ThreadState *thr, uptr sp) { + if (!thr->is_inited) // called from libc guts during bootstrap + return; + // Cleanup old bufs. + JmpBufGarbageCollect(thr, sp); + // Remember the buf. + JmpBuf *buf = thr->jmp_bufs.PushBack(); + buf->sp = sp; + buf->shadow_stack_pos = thr->shadow_stack_pos; + ThreadSignalContext *sctx = SigCtx(thr); + buf->int_signal_send = sctx ? sctx->int_signal_send : 0; + buf->in_blocking_func = sctx ? + atomic_load(&sctx->in_blocking_func, memory_order_relaxed) : + false; + buf->in_signal_handler = atomic_load(&thr->in_signal_handler, + memory_order_relaxed); +} + +static void LongJmp(ThreadState *thr, uptr *env) { + uptr sp = ExtractLongJmpSp(env); + // Find the saved buf with matching sp. + for (uptr i = 0; i < thr->jmp_bufs.Size(); i++) { + JmpBuf *buf = &thr->jmp_bufs[i]; + if (buf->sp == sp) { + CHECK_GE(thr->shadow_stack_pos, buf->shadow_stack_pos); + // Unwind the stack. + while (thr->shadow_stack_pos > buf->shadow_stack_pos) + FuncExit(thr); + ThreadSignalContext *sctx = SigCtx(thr); + if (sctx) { + sctx->int_signal_send = buf->int_signal_send; + atomic_store(&sctx->in_blocking_func, buf->in_blocking_func, + memory_order_relaxed); + } + atomic_store(&thr->in_signal_handler, buf->in_signal_handler, + memory_order_relaxed); + JmpBufGarbageCollect(thr, buf->sp - 1); // do not collect buf->sp + return; + } + } + Printf("ThreadSanitizer: can't find longjmp buf\n"); + CHECK(0); +} + +// FIXME: put everything below into a common extern "C" block? +extern "C" void __tsan_setjmp(uptr sp) { + cur_thread_init(); + SetJmp(cur_thread(), sp); +} + +#if SANITIZER_MAC +TSAN_INTERCEPTOR(int, setjmp, void *env); +TSAN_INTERCEPTOR(int, _setjmp, void *env); +TSAN_INTERCEPTOR(int, sigsetjmp, void *env); +#else // SANITIZER_MAC + +#if SANITIZER_NETBSD +#define setjmp_symname __setjmp14 +#define sigsetjmp_symname __sigsetjmp14 +#else +#define setjmp_symname setjmp +#define sigsetjmp_symname sigsetjmp +#endif + +#define TSAN_INTERCEPTOR_SETJMP_(x) __interceptor_ ## x +#define TSAN_INTERCEPTOR_SETJMP__(x) TSAN_INTERCEPTOR_SETJMP_(x) +#define TSAN_INTERCEPTOR_SETJMP TSAN_INTERCEPTOR_SETJMP__(setjmp_symname) +#define TSAN_INTERCEPTOR_SIGSETJMP TSAN_INTERCEPTOR_SETJMP__(sigsetjmp_symname) + +#define TSAN_STRING_SETJMP SANITIZER_STRINGIFY(setjmp_symname) +#define TSAN_STRING_SIGSETJMP SANITIZER_STRINGIFY(sigsetjmp_symname) + +// Not called. Merely to satisfy TSAN_INTERCEPT(). +extern "C" SANITIZER_INTERFACE_ATTRIBUTE +int TSAN_INTERCEPTOR_SETJMP(void *env); +extern "C" int TSAN_INTERCEPTOR_SETJMP(void *env) { + CHECK(0); + return 0; +} + +// FIXME: any reason to have a separate declaration? +extern "C" SANITIZER_INTERFACE_ATTRIBUTE +int __interceptor__setjmp(void *env); +extern "C" int __interceptor__setjmp(void *env) { + CHECK(0); + return 0; +} + +extern "C" SANITIZER_INTERFACE_ATTRIBUTE +int TSAN_INTERCEPTOR_SIGSETJMP(void *env); +extern "C" int TSAN_INTERCEPTOR_SIGSETJMP(void *env) { + CHECK(0); + return 0; +} + +#if !SANITIZER_NETBSD +extern "C" SANITIZER_INTERFACE_ATTRIBUTE +int __interceptor___sigsetjmp(void *env); +extern "C" int __interceptor___sigsetjmp(void *env) { + CHECK(0); + return 0; +} +#endif + +extern "C" int setjmp_symname(void *env); +extern "C" int _setjmp(void *env); +extern "C" int sigsetjmp_symname(void *env); +#if !SANITIZER_NETBSD +extern "C" int __sigsetjmp(void *env); +#endif +DEFINE_REAL(int, setjmp_symname, void *env) +DEFINE_REAL(int, _setjmp, void *env) +DEFINE_REAL(int, sigsetjmp_symname, void *env) +#if !SANITIZER_NETBSD +DEFINE_REAL(int, __sigsetjmp, void *env) +#endif +#endif // SANITIZER_MAC + +#if SANITIZER_NETBSD +#define longjmp_symname __longjmp14 +#define siglongjmp_symname __siglongjmp14 +#else +#define longjmp_symname longjmp +#define siglongjmp_symname siglongjmp +#endif + +TSAN_INTERCEPTOR(void, longjmp_symname, uptr *env, int val) { + // Note: if we call REAL(longjmp) in the context of ScopedInterceptor, + // bad things will happen. We will jump over ScopedInterceptor dtor and can + // leave thr->in_ignored_lib set. + { + SCOPED_INTERCEPTOR_RAW(longjmp_symname, env, val); + } + LongJmp(cur_thread(), env); + REAL(longjmp_symname)(env, val); +} + +TSAN_INTERCEPTOR(void, siglongjmp_symname, uptr *env, int val) { + { + SCOPED_INTERCEPTOR_RAW(siglongjmp_symname, env, val); + } + LongJmp(cur_thread(), env); + REAL(siglongjmp_symname)(env, val); +} + +#if SANITIZER_NETBSD +TSAN_INTERCEPTOR(void, _longjmp, uptr *env, int val) { + { + SCOPED_INTERCEPTOR_RAW(_longjmp, env, val); + } + LongJmp(cur_thread(), env); + REAL(_longjmp)(env, val); +} +#endif + +#if !SANITIZER_MAC +TSAN_INTERCEPTOR(void*, malloc, uptr size) { + if (in_symbolizer()) + return InternalAlloc(size); + void *p = 0; + { + SCOPED_INTERCEPTOR_RAW(malloc, size); + p = user_alloc(thr, pc, size); + } + invoke_malloc_hook(p, size); + return p; +} + +TSAN_INTERCEPTOR(void*, __libc_memalign, uptr align, uptr sz) { + SCOPED_TSAN_INTERCEPTOR(__libc_memalign, align, sz); + return user_memalign(thr, pc, align, sz); +} + +TSAN_INTERCEPTOR(void*, calloc, uptr size, uptr n) { + if (in_symbolizer()) + return InternalCalloc(size, n); + void *p = 0; + { + SCOPED_INTERCEPTOR_RAW(calloc, size, n); + p = user_calloc(thr, pc, size, n); + } + invoke_malloc_hook(p, n * size); + return p; +} + +TSAN_INTERCEPTOR(void*, realloc, void *p, uptr size) { + if (in_symbolizer()) + return InternalRealloc(p, size); + if (p) + invoke_free_hook(p); + { + SCOPED_INTERCEPTOR_RAW(realloc, p, size); + p = user_realloc(thr, pc, p, size); + } + invoke_malloc_hook(p, size); + return p; +} + +TSAN_INTERCEPTOR(void*, reallocarray, void *p, uptr size, uptr n) { + if (in_symbolizer()) + return InternalReallocArray(p, size, n); + if (p) + invoke_free_hook(p); + { + SCOPED_INTERCEPTOR_RAW(reallocarray, p, size, n); + p = user_reallocarray(thr, pc, p, size, n); + } + invoke_malloc_hook(p, size); + return p; +} + +TSAN_INTERCEPTOR(void, free, void *p) { + if (p == 0) + return; + if (in_symbolizer()) + return InternalFree(p); + invoke_free_hook(p); + SCOPED_INTERCEPTOR_RAW(free, p); + user_free(thr, pc, p); +} + +TSAN_INTERCEPTOR(void, cfree, void *p) { + if (p == 0) + return; + if (in_symbolizer()) + return InternalFree(p); + invoke_free_hook(p); + SCOPED_INTERCEPTOR_RAW(cfree, p); + user_free(thr, pc, p); +} + +TSAN_INTERCEPTOR(uptr, malloc_usable_size, void *p) { + SCOPED_INTERCEPTOR_RAW(malloc_usable_size, p); + return user_alloc_usable_size(p); +} +#endif + +TSAN_INTERCEPTOR(char *, strcpy, char *dst, const char *src) { + SCOPED_TSAN_INTERCEPTOR(strcpy, dst, src); + uptr srclen = internal_strlen(src); + MemoryAccessRange(thr, pc, (uptr)dst, srclen + 1, true); + MemoryAccessRange(thr, pc, (uptr)src, srclen + 1, false); + return REAL(strcpy)(dst, src); +} + +TSAN_INTERCEPTOR(char*, strncpy, char *dst, char *src, uptr n) { + SCOPED_TSAN_INTERCEPTOR(strncpy, dst, src, n); + uptr srclen = internal_strnlen(src, n); + MemoryAccessRange(thr, pc, (uptr)dst, n, true); + MemoryAccessRange(thr, pc, (uptr)src, min(srclen + 1, n), false); + return REAL(strncpy)(dst, src, n); +} + +TSAN_INTERCEPTOR(char*, strdup, const char *str) { + SCOPED_TSAN_INTERCEPTOR(strdup, str); + // strdup will call malloc, so no instrumentation is required here. + return REAL(strdup)(str); +} + +// Zero out addr if it points into shadow memory and was provided as a hint +// only, i.e., MAP_FIXED is not set. +static bool fix_mmap_addr(void **addr, long_t sz, int flags) { + if (*addr) { + if (!IsAppMem((uptr)*addr) || !IsAppMem((uptr)*addr + sz - 1)) { + if (flags & MAP_FIXED) { + errno = errno_EINVAL; + return false; + } else { + *addr = 0; + } + } + } + return true; +} + +template +static void *mmap_interceptor(ThreadState *thr, uptr pc, Mmap real_mmap, + void *addr, SIZE_T sz, int prot, int flags, + int fd, OFF64_T off) { + if (!fix_mmap_addr(&addr, sz, flags)) return MAP_FAILED; + void *res = real_mmap(addr, sz, prot, flags, fd, off); + if (res != MAP_FAILED) { + if (fd > 0) FdAccess(thr, pc, fd); + MemoryRangeImitateWriteOrResetRange(thr, pc, (uptr)res, sz); + } + return res; +} + +TSAN_INTERCEPTOR(int, munmap, void *addr, long_t sz) { + SCOPED_TSAN_INTERCEPTOR(munmap, addr, sz); + UnmapShadow(thr, (uptr)addr, sz); + int res = REAL(munmap)(addr, sz); + return res; +} + +#if SANITIZER_LINUX +TSAN_INTERCEPTOR(void*, memalign, uptr align, uptr sz) { + SCOPED_INTERCEPTOR_RAW(memalign, align, sz); + return user_memalign(thr, pc, align, sz); +} +#define TSAN_MAYBE_INTERCEPT_MEMALIGN TSAN_INTERCEPT(memalign) +#else +#define TSAN_MAYBE_INTERCEPT_MEMALIGN +#endif + +#if !SANITIZER_MAC +TSAN_INTERCEPTOR(void*, aligned_alloc, uptr align, uptr sz) { + if (in_symbolizer()) + return InternalAlloc(sz, nullptr, align); + SCOPED_INTERCEPTOR_RAW(aligned_alloc, align, sz); + return user_aligned_alloc(thr, pc, align, sz); +} + +TSAN_INTERCEPTOR(void*, valloc, uptr sz) { + if (in_symbolizer()) + return InternalAlloc(sz, nullptr, GetPageSizeCached()); + SCOPED_INTERCEPTOR_RAW(valloc, sz); + return user_valloc(thr, pc, sz); +} +#endif + +#if SANITIZER_LINUX +TSAN_INTERCEPTOR(void*, pvalloc, uptr sz) { + if (in_symbolizer()) { + uptr PageSize = GetPageSizeCached(); + sz = sz ? RoundUpTo(sz, PageSize) : PageSize; + return InternalAlloc(sz, nullptr, PageSize); + } + SCOPED_INTERCEPTOR_RAW(pvalloc, sz); + return user_pvalloc(thr, pc, sz); +} +#define TSAN_MAYBE_INTERCEPT_PVALLOC TSAN_INTERCEPT(pvalloc) +#else +#define TSAN_MAYBE_INTERCEPT_PVALLOC +#endif + +#if !SANITIZER_MAC +TSAN_INTERCEPTOR(int, posix_memalign, void **memptr, uptr align, uptr sz) { + if (in_symbolizer()) { + void *p = InternalAlloc(sz, nullptr, align); + if (!p) + return errno_ENOMEM; + *memptr = p; + return 0; + } + SCOPED_INTERCEPTOR_RAW(posix_memalign, memptr, align, sz); + return user_posix_memalign(thr, pc, memptr, align, sz); +} +#endif + +// __cxa_guard_acquire and friends need to be intercepted in a special way - +// regular interceptors will break statically-linked libstdc++. Linux +// interceptors are especially defined as weak functions (so that they don't +// cause link errors when user defines them as well). So they silently +// auto-disable themselves when such symbol is already present in the binary. If +// we link libstdc++ statically, it will bring own __cxa_guard_acquire which +// will silently replace our interceptor. That's why on Linux we simply export +// these interceptors with INTERFACE_ATTRIBUTE. +// On OS X, we don't support statically linking, so we just use a regular +// interceptor. +#if SANITIZER_MAC +#define STDCXX_INTERCEPTOR TSAN_INTERCEPTOR +#else +#define STDCXX_INTERCEPTOR(rettype, name, ...) \ + extern "C" rettype INTERFACE_ATTRIBUTE name(__VA_ARGS__) +#endif + +// Used in thread-safe function static initialization. +STDCXX_INTERCEPTOR(int, __cxa_guard_acquire, atomic_uint32_t *g) { + SCOPED_INTERCEPTOR_RAW(__cxa_guard_acquire, g); + OnPotentiallyBlockingRegionBegin(); + auto on_exit = at_scope_exit(&OnPotentiallyBlockingRegionEnd); + for (;;) { + u32 cmp = atomic_load(g, memory_order_acquire); + if (cmp == 0) { + if (atomic_compare_exchange_strong(g, &cmp, 1<<16, memory_order_relaxed)) + return 1; + } else if (cmp == 1) { + Acquire(thr, pc, (uptr)g); + return 0; + } else { + internal_sched_yield(); + } + } +} + +STDCXX_INTERCEPTOR(void, __cxa_guard_release, atomic_uint32_t *g) { + SCOPED_INTERCEPTOR_RAW(__cxa_guard_release, g); + Release(thr, pc, (uptr)g); + atomic_store(g, 1, memory_order_release); +} + +STDCXX_INTERCEPTOR(void, __cxa_guard_abort, atomic_uint32_t *g) { + SCOPED_INTERCEPTOR_RAW(__cxa_guard_abort, g); + atomic_store(g, 0, memory_order_relaxed); +} + +namespace __tsan { +void DestroyThreadState() { + ThreadState *thr = cur_thread(); + Processor *proc = thr->proc(); + ThreadFinish(thr); + ProcUnwire(proc, thr); + ProcDestroy(proc); + ThreadSignalContext *sctx = thr->signal_ctx; + if (sctx) { + thr->signal_ctx = 0; + UnmapOrDie(sctx, sizeof(*sctx)); + } + DTLS_Destroy(); + cur_thread_finalize(); +} +} // namespace __tsan + +#if !SANITIZER_MAC && !SANITIZER_NETBSD && !SANITIZER_FREEBSD +static void thread_finalize(void *v) { + uptr iter = (uptr)v; + if (iter > 1) { + if (pthread_setspecific(interceptor_ctx()->finalize_key, + (void*)(iter - 1))) { + Printf("ThreadSanitizer: failed to set thread key\n"); + Die(); + } + return; + } + DestroyThreadState(); +} +#endif + + +struct ThreadParam { + void* (*callback)(void *arg); + void *param; + atomic_uintptr_t tid; +}; + +extern "C" void *__tsan_thread_start_func(void *arg) { + ThreadParam *p = (ThreadParam*)arg; + void* (*callback)(void *arg) = p->callback; + void *param = p->param; + int tid = 0; + { + cur_thread_init(); + ThreadState *thr = cur_thread(); + // Thread-local state is not initialized yet. + ScopedIgnoreInterceptors ignore; +#if !SANITIZER_MAC && !SANITIZER_NETBSD && !SANITIZER_FREEBSD + ThreadIgnoreBegin(thr, 0); + if (pthread_setspecific(interceptor_ctx()->finalize_key, + (void *)GetPthreadDestructorIterations())) { + Printf("ThreadSanitizer: failed to set thread key\n"); + Die(); + } + ThreadIgnoreEnd(thr, 0); +#endif + while ((tid = atomic_load(&p->tid, memory_order_acquire)) == 0) + internal_sched_yield(); + Processor *proc = ProcCreate(); + ProcWire(proc, thr); + ThreadStart(thr, tid, GetTid(), ThreadType::Regular); + atomic_store(&p->tid, 0, memory_order_release); + } + void *res = callback(param); + // Prevent the callback from being tail called, + // it mixes up stack traces. + volatile int foo = 42; + foo++; + return res; +} + +TSAN_INTERCEPTOR(int, pthread_create, + void *th, void *attr, void *(*callback)(void*), void * param) { + SCOPED_INTERCEPTOR_RAW(pthread_create, th, attr, callback, param); + + MaybeSpawnBackgroundThread(); + + if (ctx->after_multithreaded_fork) { + if (flags()->die_after_fork) { + Report("ThreadSanitizer: starting new threads after multi-threaded " + "fork is not supported. Dying (set die_after_fork=0 to override)\n"); + Die(); + } else { + VPrintf(1, "ThreadSanitizer: starting new threads after multi-threaded " + "fork is not supported (pid %d). Continuing because of " + "die_after_fork=0, but you are on your own\n", internal_getpid()); + } + } + __sanitizer_pthread_attr_t myattr; + if (attr == 0) { + pthread_attr_init(&myattr); + attr = &myattr; + } + int detached = 0; + REAL(pthread_attr_getdetachstate)(attr, &detached); + AdjustStackSize(attr); + + ThreadParam p; + p.callback = callback; + p.param = param; + atomic_store(&p.tid, 0, memory_order_relaxed); + int res = -1; + { + // Otherwise we see false positives in pthread stack manipulation. + ScopedIgnoreInterceptors ignore; + ThreadIgnoreBegin(thr, pc); + res = REAL(pthread_create)(th, attr, __tsan_thread_start_func, &p); + ThreadIgnoreEnd(thr, pc); + } + if (res == 0) { + int tid = ThreadCreate(thr, pc, *(uptr*)th, IsStateDetached(detached)); + CHECK_NE(tid, 0); + // Synchronization on p.tid serves two purposes: + // 1. ThreadCreate must finish before the new thread starts. + // Otherwise the new thread can call pthread_detach, but the pthread_t + // identifier is not yet registered in ThreadRegistry by ThreadCreate. + // 2. ThreadStart must finish before this thread continues. + // Otherwise, this thread can call pthread_detach and reset thr->sync + // before the new thread got a chance to acquire from it in ThreadStart. + atomic_store(&p.tid, tid, memory_order_release); + while (atomic_load(&p.tid, memory_order_acquire) != 0) + internal_sched_yield(); + } + if (attr == &myattr) + pthread_attr_destroy(&myattr); + return res; +} + +TSAN_INTERCEPTOR(int, pthread_join, void *th, void **ret) { + SCOPED_INTERCEPTOR_RAW(pthread_join, th, ret); + int tid = ThreadTid(thr, pc, (uptr)th); + ThreadIgnoreBegin(thr, pc); + int res = BLOCK_REAL(pthread_join)(th, ret); + ThreadIgnoreEnd(thr, pc); + if (res == 0) { + ThreadJoin(thr, pc, tid); + } + return res; +} + +DEFINE_REAL_PTHREAD_FUNCTIONS + +TSAN_INTERCEPTOR(int, pthread_detach, void *th) { + SCOPED_TSAN_INTERCEPTOR(pthread_detach, th); + int tid = ThreadTid(thr, pc, (uptr)th); + int res = REAL(pthread_detach)(th); + if (res == 0) { + ThreadDetach(thr, pc, tid); + } + return res; +} + +TSAN_INTERCEPTOR(void, pthread_exit, void *retval) { + { + SCOPED_INTERCEPTOR_RAW(pthread_exit, retval); +#if !SANITIZER_MAC && !SANITIZER_ANDROID + CHECK_EQ(thr, &cur_thread_placeholder); +#endif + } + REAL(pthread_exit)(retval); +} + +#if SANITIZER_LINUX +TSAN_INTERCEPTOR(int, pthread_tryjoin_np, void *th, void **ret) { + SCOPED_TSAN_INTERCEPTOR(pthread_tryjoin_np, th, ret); + int tid = ThreadTid(thr, pc, (uptr)th); + ThreadIgnoreBegin(thr, pc); + int res = REAL(pthread_tryjoin_np)(th, ret); + ThreadIgnoreEnd(thr, pc); + if (res == 0) + ThreadJoin(thr, pc, tid); + else + ThreadNotJoined(thr, pc, tid, (uptr)th); + return res; +} + +TSAN_INTERCEPTOR(int, pthread_timedjoin_np, void *th, void **ret, + const struct timespec *abstime) { + SCOPED_TSAN_INTERCEPTOR(pthread_timedjoin_np, th, ret, abstime); + int tid = ThreadTid(thr, pc, (uptr)th); + ThreadIgnoreBegin(thr, pc); + int res = BLOCK_REAL(pthread_timedjoin_np)(th, ret, abstime); + ThreadIgnoreEnd(thr, pc); + if (res == 0) + ThreadJoin(thr, pc, tid); + else + ThreadNotJoined(thr, pc, tid, (uptr)th); + return res; +} +#endif + +// Problem: +// NPTL implementation of pthread_cond has 2 versions (2.2.5 and 2.3.2). +// pthread_cond_t has different size in the different versions. +// If call new REAL functions for old pthread_cond_t, they will corrupt memory +// after pthread_cond_t (old cond is smaller). +// If we call old REAL functions for new pthread_cond_t, we will lose some +// functionality (e.g. old functions do not support waiting against +// CLOCK_REALTIME). +// Proper handling would require to have 2 versions of interceptors as well. +// But this is messy, in particular requires linker scripts when sanitizer +// runtime is linked into a shared library. +// Instead we assume we don't have dynamic libraries built against old +// pthread (2.2.5 is dated by 2002). And provide legacy_pthread_cond flag +// that allows to work with old libraries (but this mode does not support +// some features, e.g. pthread_condattr_getpshared). +static void *init_cond(void *c, bool force = false) { + // sizeof(pthread_cond_t) >= sizeof(uptr) in both versions. + // So we allocate additional memory on the side large enough to hold + // any pthread_cond_t object. Always call new REAL functions, but pass + // the aux object to them. + // Note: the code assumes that PTHREAD_COND_INITIALIZER initializes + // first word of pthread_cond_t to zero. + // It's all relevant only for linux. + if (!common_flags()->legacy_pthread_cond) + return c; + atomic_uintptr_t *p = (atomic_uintptr_t*)c; + uptr cond = atomic_load(p, memory_order_acquire); + if (!force && cond != 0) + return (void*)cond; + void *newcond = WRAP(malloc)(pthread_cond_t_sz); + internal_memset(newcond, 0, pthread_cond_t_sz); + if (atomic_compare_exchange_strong(p, &cond, (uptr)newcond, + memory_order_acq_rel)) + return newcond; + WRAP(free)(newcond); + return (void*)cond; +} + +struct CondMutexUnlockCtx { + ScopedInterceptor *si; + ThreadState *thr; + uptr pc; + void *m; +}; + +static void cond_mutex_unlock(CondMutexUnlockCtx *arg) { + // pthread_cond_wait interceptor has enabled async signal delivery + // (see BlockingCall below). Disable async signals since we are running + // tsan code. Also ScopedInterceptor and BlockingCall destructors won't run + // since the thread is cancelled, so we have to manually execute them + // (the thread still can run some user code due to pthread_cleanup_push). + ThreadSignalContext *ctx = SigCtx(arg->thr); + CHECK_EQ(atomic_load(&ctx->in_blocking_func, memory_order_relaxed), 1); + atomic_store(&ctx->in_blocking_func, 0, memory_order_relaxed); + MutexPostLock(arg->thr, arg->pc, (uptr)arg->m, MutexFlagDoPreLockOnPostLock); + // Undo BlockingCall ctor effects. + arg->thr->ignore_interceptors--; + arg->si->~ScopedInterceptor(); +} + +INTERCEPTOR(int, pthread_cond_init, void *c, void *a) { + void *cond = init_cond(c, true); + SCOPED_TSAN_INTERCEPTOR(pthread_cond_init, cond, a); + MemoryAccessRange(thr, pc, (uptr)c, sizeof(uptr), true); + return REAL(pthread_cond_init)(cond, a); +} + +static int cond_wait(ThreadState *thr, uptr pc, ScopedInterceptor *si, + int (*fn)(void *c, void *m, void *abstime), void *c, + void *m, void *t) { + MemoryAccessRange(thr, pc, (uptr)c, sizeof(uptr), false); + MutexUnlock(thr, pc, (uptr)m); + CondMutexUnlockCtx arg = {si, thr, pc, m}; + int res = 0; + // This ensures that we handle mutex lock even in case of pthread_cancel. + // See test/tsan/cond_cancel.cpp. + { + // Enable signal delivery while the thread is blocked. + BlockingCall bc(thr); + res = call_pthread_cancel_with_cleanup( + fn, c, m, t, (void (*)(void *arg))cond_mutex_unlock, &arg); + } + if (res == errno_EOWNERDEAD) MutexRepair(thr, pc, (uptr)m); + MutexPostLock(thr, pc, (uptr)m, MutexFlagDoPreLockOnPostLock); + return res; +} + +INTERCEPTOR(int, pthread_cond_wait, void *c, void *m) { + void *cond = init_cond(c); + SCOPED_TSAN_INTERCEPTOR(pthread_cond_wait, cond, m); + return cond_wait(thr, pc, &si, (int (*)(void *c, void *m, void *abstime))REAL( + pthread_cond_wait), + cond, m, 0); +} + +INTERCEPTOR(int, pthread_cond_timedwait, void *c, void *m, void *abstime) { + void *cond = init_cond(c); + SCOPED_TSAN_INTERCEPTOR(pthread_cond_timedwait, cond, m, abstime); + return cond_wait(thr, pc, &si, REAL(pthread_cond_timedwait), cond, m, + abstime); +} + +#if SANITIZER_MAC +INTERCEPTOR(int, pthread_cond_timedwait_relative_np, void *c, void *m, + void *reltime) { + void *cond = init_cond(c); + SCOPED_TSAN_INTERCEPTOR(pthread_cond_timedwait_relative_np, cond, m, reltime); + return cond_wait(thr, pc, &si, REAL(pthread_cond_timedwait_relative_np), cond, + m, reltime); +} +#endif + +INTERCEPTOR(int, pthread_cond_signal, void *c) { + void *cond = init_cond(c); + SCOPED_TSAN_INTERCEPTOR(pthread_cond_signal, cond); + MemoryAccessRange(thr, pc, (uptr)c, sizeof(uptr), false); + return REAL(pthread_cond_signal)(cond); +} + +INTERCEPTOR(int, pthread_cond_broadcast, void *c) { + void *cond = init_cond(c); + SCOPED_TSAN_INTERCEPTOR(pthread_cond_broadcast, cond); + MemoryAccessRange(thr, pc, (uptr)c, sizeof(uptr), false); + return REAL(pthread_cond_broadcast)(cond); +} + +INTERCEPTOR(int, pthread_cond_destroy, void *c) { + void *cond = init_cond(c); + SCOPED_TSAN_INTERCEPTOR(pthread_cond_destroy, cond); + MemoryAccessRange(thr, pc, (uptr)c, sizeof(uptr), true); + int res = REAL(pthread_cond_destroy)(cond); + if (common_flags()->legacy_pthread_cond) { + // Free our aux cond and zero the pointer to not leave dangling pointers. + WRAP(free)(cond); + atomic_store((atomic_uintptr_t*)c, 0, memory_order_relaxed); + } + return res; +} + +TSAN_INTERCEPTOR(int, pthread_mutex_init, void *m, void *a) { + SCOPED_TSAN_INTERCEPTOR(pthread_mutex_init, m, a); + int res = REAL(pthread_mutex_init)(m, a); + if (res == 0) { + u32 flagz = 0; + if (a) { + int type = 0; + if (REAL(pthread_mutexattr_gettype)(a, &type) == 0) + if (type == PTHREAD_MUTEX_RECURSIVE || + type == PTHREAD_MUTEX_RECURSIVE_NP) + flagz |= MutexFlagWriteReentrant; + } + MutexCreate(thr, pc, (uptr)m, flagz); + } + return res; +} + +TSAN_INTERCEPTOR(int, pthread_mutex_destroy, void *m) { + SCOPED_TSAN_INTERCEPTOR(pthread_mutex_destroy, m); + int res = REAL(pthread_mutex_destroy)(m); + if (res == 0 || res == errno_EBUSY) { + MutexDestroy(thr, pc, (uptr)m); + } + return res; +} + +TSAN_INTERCEPTOR(int, pthread_mutex_trylock, void *m) { + SCOPED_TSAN_INTERCEPTOR(pthread_mutex_trylock, m); + int res = REAL(pthread_mutex_trylock)(m); + if (res == errno_EOWNERDEAD) + MutexRepair(thr, pc, (uptr)m); + if (res == 0 || res == errno_EOWNERDEAD) + MutexPostLock(thr, pc, (uptr)m, MutexFlagTryLock); + return res; +} + +#if !SANITIZER_MAC +TSAN_INTERCEPTOR(int, pthread_mutex_timedlock, void *m, void *abstime) { + SCOPED_TSAN_INTERCEPTOR(pthread_mutex_timedlock, m, abstime); + int res = REAL(pthread_mutex_timedlock)(m, abstime); + if (res == 0) { + MutexPostLock(thr, pc, (uptr)m, MutexFlagTryLock); + } + return res; +} +#endif + +#if !SANITIZER_MAC +TSAN_INTERCEPTOR(int, pthread_spin_init, void *m, int pshared) { + SCOPED_TSAN_INTERCEPTOR(pthread_spin_init, m, pshared); + int res = REAL(pthread_spin_init)(m, pshared); + if (res == 0) { + MutexCreate(thr, pc, (uptr)m); + } + return res; +} + +TSAN_INTERCEPTOR(int, pthread_spin_destroy, void *m) { + SCOPED_TSAN_INTERCEPTOR(pthread_spin_destroy, m); + int res = REAL(pthread_spin_destroy)(m); + if (res == 0) { + MutexDestroy(thr, pc, (uptr)m); + } + return res; +} + +TSAN_INTERCEPTOR(int, pthread_spin_lock, void *m) { + SCOPED_TSAN_INTERCEPTOR(pthread_spin_lock, m); + MutexPreLock(thr, pc, (uptr)m); + int res = REAL(pthread_spin_lock)(m); + if (res == 0) { + MutexPostLock(thr, pc, (uptr)m); + } + return res; +} + +TSAN_INTERCEPTOR(int, pthread_spin_trylock, void *m) { + SCOPED_TSAN_INTERCEPTOR(pthread_spin_trylock, m); + int res = REAL(pthread_spin_trylock)(m); + if (res == 0) { + MutexPostLock(thr, pc, (uptr)m, MutexFlagTryLock); + } + return res; +} + +TSAN_INTERCEPTOR(int, pthread_spin_unlock, void *m) { + SCOPED_TSAN_INTERCEPTOR(pthread_spin_unlock, m); + MutexUnlock(thr, pc, (uptr)m); + int res = REAL(pthread_spin_unlock)(m); + return res; +} +#endif + +TSAN_INTERCEPTOR(int, pthread_rwlock_init, void *m, void *a) { + SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_init, m, a); + int res = REAL(pthread_rwlock_init)(m, a); + if (res == 0) { + MutexCreate(thr, pc, (uptr)m); + } + return res; +} + +TSAN_INTERCEPTOR(int, pthread_rwlock_destroy, void *m) { + SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_destroy, m); + int res = REAL(pthread_rwlock_destroy)(m); + if (res == 0) { + MutexDestroy(thr, pc, (uptr)m); + } + return res; +} + +TSAN_INTERCEPTOR(int, pthread_rwlock_rdlock, void *m) { + SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_rdlock, m); + MutexPreReadLock(thr, pc, (uptr)m); + int res = REAL(pthread_rwlock_rdlock)(m); + if (res == 0) { + MutexPostReadLock(thr, pc, (uptr)m); + } + return res; +} + +TSAN_INTERCEPTOR(int, pthread_rwlock_tryrdlock, void *m) { + SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_tryrdlock, m); + int res = REAL(pthread_rwlock_tryrdlock)(m); + if (res == 0) { + MutexPostReadLock(thr, pc, (uptr)m, MutexFlagTryLock); + } + return res; +} + +#if !SANITIZER_MAC +TSAN_INTERCEPTOR(int, pthread_rwlock_timedrdlock, void *m, void *abstime) { + SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_timedrdlock, m, abstime); + int res = REAL(pthread_rwlock_timedrdlock)(m, abstime); + if (res == 0) { + MutexPostReadLock(thr, pc, (uptr)m); + } + return res; +} +#endif + +TSAN_INTERCEPTOR(int, pthread_rwlock_wrlock, void *m) { + SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_wrlock, m); + MutexPreLock(thr, pc, (uptr)m); + int res = REAL(pthread_rwlock_wrlock)(m); + if (res == 0) { + MutexPostLock(thr, pc, (uptr)m); + } + return res; +} + +TSAN_INTERCEPTOR(int, pthread_rwlock_trywrlock, void *m) { + SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_trywrlock, m); + int res = REAL(pthread_rwlock_trywrlock)(m); + if (res == 0) { + MutexPostLock(thr, pc, (uptr)m, MutexFlagTryLock); + } + return res; +} + +#if !SANITIZER_MAC +TSAN_INTERCEPTOR(int, pthread_rwlock_timedwrlock, void *m, void *abstime) { + SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_timedwrlock, m, abstime); + int res = REAL(pthread_rwlock_timedwrlock)(m, abstime); + if (res == 0) { + MutexPostLock(thr, pc, (uptr)m, MutexFlagTryLock); + } + return res; +} +#endif + +TSAN_INTERCEPTOR(int, pthread_rwlock_unlock, void *m) { + SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_unlock, m); + MutexReadOrWriteUnlock(thr, pc, (uptr)m); + int res = REAL(pthread_rwlock_unlock)(m); + return res; +} + +#if !SANITIZER_MAC +TSAN_INTERCEPTOR(int, pthread_barrier_init, void *b, void *a, unsigned count) { + SCOPED_TSAN_INTERCEPTOR(pthread_barrier_init, b, a, count); + MemoryWrite(thr, pc, (uptr)b, kSizeLog1); + int res = REAL(pthread_barrier_init)(b, a, count); + return res; +} + +TSAN_INTERCEPTOR(int, pthread_barrier_destroy, void *b) { + SCOPED_TSAN_INTERCEPTOR(pthread_barrier_destroy, b); + MemoryWrite(thr, pc, (uptr)b, kSizeLog1); + int res = REAL(pthread_barrier_destroy)(b); + return res; +} + +TSAN_INTERCEPTOR(int, pthread_barrier_wait, void *b) { + SCOPED_TSAN_INTERCEPTOR(pthread_barrier_wait, b); + Release(thr, pc, (uptr)b); + MemoryRead(thr, pc, (uptr)b, kSizeLog1); + int res = REAL(pthread_barrier_wait)(b); + MemoryRead(thr, pc, (uptr)b, kSizeLog1); + if (res == 0 || res == PTHREAD_BARRIER_SERIAL_THREAD) { + Acquire(thr, pc, (uptr)b); + } + return res; +} +#endif + +TSAN_INTERCEPTOR(int, pthread_once, void *o, void (*f)()) { + SCOPED_INTERCEPTOR_RAW(pthread_once, o, f); + if (o == 0 || f == 0) + return errno_EINVAL; + atomic_uint32_t *a; + + if (SANITIZER_MAC) + a = static_cast((void *)((char *)o + sizeof(long_t))); + else if (SANITIZER_NETBSD) + a = static_cast + ((void *)((char *)o + __sanitizer::pthread_mutex_t_sz)); + else + a = static_cast(o); + + u32 v = atomic_load(a, memory_order_acquire); + if (v == 0 && atomic_compare_exchange_strong(a, &v, 1, + memory_order_relaxed)) { + (*f)(); + if (!thr->in_ignored_lib) + Release(thr, pc, (uptr)o); + atomic_store(a, 2, memory_order_release); + } else { + while (v != 2) { + internal_sched_yield(); + v = atomic_load(a, memory_order_acquire); + } + if (!thr->in_ignored_lib) + Acquire(thr, pc, (uptr)o); + } + return 0; +} + +#if SANITIZER_LINUX && !SANITIZER_ANDROID +TSAN_INTERCEPTOR(int, __fxstat, int version, int fd, void *buf) { + SCOPED_TSAN_INTERCEPTOR(__fxstat, version, fd, buf); + if (fd > 0) + FdAccess(thr, pc, fd); + return REAL(__fxstat)(version, fd, buf); +} +#define TSAN_MAYBE_INTERCEPT___FXSTAT TSAN_INTERCEPT(__fxstat) +#else +#define TSAN_MAYBE_INTERCEPT___FXSTAT +#endif + +TSAN_INTERCEPTOR(int, fstat, int fd, void *buf) { +#if SANITIZER_FREEBSD || SANITIZER_MAC || SANITIZER_ANDROID || SANITIZER_NETBSD + SCOPED_TSAN_INTERCEPTOR(fstat, fd, buf); + if (fd > 0) + FdAccess(thr, pc, fd); + return REAL(fstat)(fd, buf); +#else + SCOPED_TSAN_INTERCEPTOR(__fxstat, 0, fd, buf); + if (fd > 0) + FdAccess(thr, pc, fd); + return REAL(__fxstat)(0, fd, buf); +#endif +} + +#if SANITIZER_LINUX && !SANITIZER_ANDROID +TSAN_INTERCEPTOR(int, __fxstat64, int version, int fd, void *buf) { + SCOPED_TSAN_INTERCEPTOR(__fxstat64, version, fd, buf); + if (fd > 0) + FdAccess(thr, pc, fd); + return REAL(__fxstat64)(version, fd, buf); +} +#define TSAN_MAYBE_INTERCEPT___FXSTAT64 TSAN_INTERCEPT(__fxstat64) +#else +#define TSAN_MAYBE_INTERCEPT___FXSTAT64 +#endif + +#if SANITIZER_LINUX && !SANITIZER_ANDROID +TSAN_INTERCEPTOR(int, fstat64, int fd, void *buf) { + SCOPED_TSAN_INTERCEPTOR(__fxstat64, 0, fd, buf); + if (fd > 0) + FdAccess(thr, pc, fd); + return REAL(__fxstat64)(0, fd, buf); +} +#define TSAN_MAYBE_INTERCEPT_FSTAT64 TSAN_INTERCEPT(fstat64) +#else +#define TSAN_MAYBE_INTERCEPT_FSTAT64 +#endif + +TSAN_INTERCEPTOR(int, open, const char *name, int flags, int mode) { + SCOPED_TSAN_INTERCEPTOR(open, name, flags, mode); + READ_STRING(thr, pc, name, 0); + int fd = REAL(open)(name, flags, mode); + if (fd >= 0) + FdFileCreate(thr, pc, fd); + return fd; +} + +#if SANITIZER_LINUX +TSAN_INTERCEPTOR(int, open64, const char *name, int flags, int mode) { + SCOPED_TSAN_INTERCEPTOR(open64, name, flags, mode); + READ_STRING(thr, pc, name, 0); + int fd = REAL(open64)(name, flags, mode); + if (fd >= 0) + FdFileCreate(thr, pc, fd); + return fd; +} +#define TSAN_MAYBE_INTERCEPT_OPEN64 TSAN_INTERCEPT(open64) +#else +#define TSAN_MAYBE_INTERCEPT_OPEN64 +#endif + +TSAN_INTERCEPTOR(int, creat, const char *name, int mode) { + SCOPED_TSAN_INTERCEPTOR(creat, name, mode); + READ_STRING(thr, pc, name, 0); + int fd = REAL(creat)(name, mode); + if (fd >= 0) + FdFileCreate(thr, pc, fd); + return fd; +} + +#if SANITIZER_LINUX +TSAN_INTERCEPTOR(int, creat64, const char *name, int mode) { + SCOPED_TSAN_INTERCEPTOR(creat64, name, mode); + READ_STRING(thr, pc, name, 0); + int fd = REAL(creat64)(name, mode); + if (fd >= 0) + FdFileCreate(thr, pc, fd); + return fd; +} +#define TSAN_MAYBE_INTERCEPT_CREAT64 TSAN_INTERCEPT(creat64) +#else +#define TSAN_MAYBE_INTERCEPT_CREAT64 +#endif + +TSAN_INTERCEPTOR(int, dup, int oldfd) { + SCOPED_TSAN_INTERCEPTOR(dup, oldfd); + int newfd = REAL(dup)(oldfd); + if (oldfd >= 0 && newfd >= 0 && newfd != oldfd) + FdDup(thr, pc, oldfd, newfd, true); + return newfd; +} + +TSAN_INTERCEPTOR(int, dup2, int oldfd, int newfd) { + SCOPED_TSAN_INTERCEPTOR(dup2, oldfd, newfd); + int newfd2 = REAL(dup2)(oldfd, newfd); + if (oldfd >= 0 && newfd2 >= 0 && newfd2 != oldfd) + FdDup(thr, pc, oldfd, newfd2, false); + return newfd2; +} + +#if !SANITIZER_MAC +TSAN_INTERCEPTOR(int, dup3, int oldfd, int newfd, int flags) { + SCOPED_TSAN_INTERCEPTOR(dup3, oldfd, newfd, flags); + int newfd2 = REAL(dup3)(oldfd, newfd, flags); + if (oldfd >= 0 && newfd2 >= 0 && newfd2 != oldfd) + FdDup(thr, pc, oldfd, newfd2, false); + return newfd2; +} +#endif + +#if SANITIZER_LINUX +TSAN_INTERCEPTOR(int, eventfd, unsigned initval, int flags) { + SCOPED_TSAN_INTERCEPTOR(eventfd, initval, flags); + int fd = REAL(eventfd)(initval, flags); + if (fd >= 0) + FdEventCreate(thr, pc, fd); + return fd; +} +#define TSAN_MAYBE_INTERCEPT_EVENTFD TSAN_INTERCEPT(eventfd) +#else +#define TSAN_MAYBE_INTERCEPT_EVENTFD +#endif + +#if SANITIZER_LINUX +TSAN_INTERCEPTOR(int, signalfd, int fd, void *mask, int flags) { + SCOPED_TSAN_INTERCEPTOR(signalfd, fd, mask, flags); + if (fd >= 0) + FdClose(thr, pc, fd); + fd = REAL(signalfd)(fd, mask, flags); + if (fd >= 0) + FdSignalCreate(thr, pc, fd); + return fd; +} +#define TSAN_MAYBE_INTERCEPT_SIGNALFD TSAN_INTERCEPT(signalfd) +#else +#define TSAN_MAYBE_INTERCEPT_SIGNALFD +#endif + +#if SANITIZER_LINUX +TSAN_INTERCEPTOR(int, inotify_init, int fake) { + SCOPED_TSAN_INTERCEPTOR(inotify_init, fake); + int fd = REAL(inotify_init)(fake); + if (fd >= 0) + FdInotifyCreate(thr, pc, fd); + return fd; +} +#define TSAN_MAYBE_INTERCEPT_INOTIFY_INIT TSAN_INTERCEPT(inotify_init) +#else +#define TSAN_MAYBE_INTERCEPT_INOTIFY_INIT +#endif + +#if SANITIZER_LINUX +TSAN_INTERCEPTOR(int, inotify_init1, int flags) { + SCOPED_TSAN_INTERCEPTOR(inotify_init1, flags); + int fd = REAL(inotify_init1)(flags); + if (fd >= 0) + FdInotifyCreate(thr, pc, fd); + return fd; +} +#define TSAN_MAYBE_INTERCEPT_INOTIFY_INIT1 TSAN_INTERCEPT(inotify_init1) +#else +#define TSAN_MAYBE_INTERCEPT_INOTIFY_INIT1 +#endif + +TSAN_INTERCEPTOR(int, socket, int domain, int type, int protocol) { + SCOPED_TSAN_INTERCEPTOR(socket, domain, type, protocol); + int fd = REAL(socket)(domain, type, protocol); + if (fd >= 0) + FdSocketCreate(thr, pc, fd); + return fd; +} + +TSAN_INTERCEPTOR(int, socketpair, int domain, int type, int protocol, int *fd) { + SCOPED_TSAN_INTERCEPTOR(socketpair, domain, type, protocol, fd); + int res = REAL(socketpair)(domain, type, protocol, fd); + if (res == 0 && fd[0] >= 0 && fd[1] >= 0) + FdPipeCreate(thr, pc, fd[0], fd[1]); + return res; +} + +TSAN_INTERCEPTOR(int, connect, int fd, void *addr, unsigned addrlen) { + SCOPED_TSAN_INTERCEPTOR(connect, fd, addr, addrlen); + FdSocketConnecting(thr, pc, fd); + int res = REAL(connect)(fd, addr, addrlen); + if (res == 0 && fd >= 0) + FdSocketConnect(thr, pc, fd); + return res; +} + +TSAN_INTERCEPTOR(int, bind, int fd, void *addr, unsigned addrlen) { + SCOPED_TSAN_INTERCEPTOR(bind, fd, addr, addrlen); + int res = REAL(bind)(fd, addr, addrlen); + if (fd > 0 && res == 0) + FdAccess(thr, pc, fd); + return res; +} + +TSAN_INTERCEPTOR(int, listen, int fd, int backlog) { + SCOPED_TSAN_INTERCEPTOR(listen, fd, backlog); + int res = REAL(listen)(fd, backlog); + if (fd > 0 && res == 0) + FdAccess(thr, pc, fd); + return res; +} + +TSAN_INTERCEPTOR(int, close, int fd) { + SCOPED_TSAN_INTERCEPTOR(close, fd); + if (fd >= 0) + FdClose(thr, pc, fd); + return REAL(close)(fd); +} + +#if SANITIZER_LINUX +TSAN_INTERCEPTOR(int, __close, int fd) { + SCOPED_TSAN_INTERCEPTOR(__close, fd); + if (fd >= 0) + FdClose(thr, pc, fd); + return REAL(__close)(fd); +} +#define TSAN_MAYBE_INTERCEPT___CLOSE TSAN_INTERCEPT(__close) +#else +#define TSAN_MAYBE_INTERCEPT___CLOSE +#endif + +// glibc guts +#if SANITIZER_LINUX && !SANITIZER_ANDROID +TSAN_INTERCEPTOR(void, __res_iclose, void *state, bool free_addr) { + SCOPED_TSAN_INTERCEPTOR(__res_iclose, state, free_addr); + int fds[64]; + int cnt = ExtractResolvFDs(state, fds, ARRAY_SIZE(fds)); + for (int i = 0; i < cnt; i++) { + if (fds[i] > 0) + FdClose(thr, pc, fds[i]); + } + REAL(__res_iclose)(state, free_addr); +} +#define TSAN_MAYBE_INTERCEPT___RES_ICLOSE TSAN_INTERCEPT(__res_iclose) +#else +#define TSAN_MAYBE_INTERCEPT___RES_ICLOSE +#endif + +TSAN_INTERCEPTOR(int, pipe, int *pipefd) { + SCOPED_TSAN_INTERCEPTOR(pipe, pipefd); + int res = REAL(pipe)(pipefd); + if (res == 0 && pipefd[0] >= 0 && pipefd[1] >= 0) + FdPipeCreate(thr, pc, pipefd[0], pipefd[1]); + return res; +} + +#if !SANITIZER_MAC +TSAN_INTERCEPTOR(int, pipe2, int *pipefd, int flags) { + SCOPED_TSAN_INTERCEPTOR(pipe2, pipefd, flags); + int res = REAL(pipe2)(pipefd, flags); + if (res == 0 && pipefd[0] >= 0 && pipefd[1] >= 0) + FdPipeCreate(thr, pc, pipefd[0], pipefd[1]); + return res; +} +#endif + +TSAN_INTERCEPTOR(int, unlink, char *path) { + SCOPED_TSAN_INTERCEPTOR(unlink, path); + Release(thr, pc, File2addr(path)); + int res = REAL(unlink)(path); + return res; +} + +TSAN_INTERCEPTOR(void*, tmpfile, int fake) { + SCOPED_TSAN_INTERCEPTOR(tmpfile, fake); + void *res = REAL(tmpfile)(fake); + if (res) { + int fd = fileno_unlocked(res); + if (fd >= 0) + FdFileCreate(thr, pc, fd); + } + return res; +} + +#if SANITIZER_LINUX +TSAN_INTERCEPTOR(void*, tmpfile64, int fake) { + SCOPED_TSAN_INTERCEPTOR(tmpfile64, fake); + void *res = REAL(tmpfile64)(fake); + if (res) { + int fd = fileno_unlocked(res); + if (fd >= 0) + FdFileCreate(thr, pc, fd); + } + return res; +} +#define TSAN_MAYBE_INTERCEPT_TMPFILE64 TSAN_INTERCEPT(tmpfile64) +#else +#define TSAN_MAYBE_INTERCEPT_TMPFILE64 +#endif + +static void FlushStreams() { + // Flushing all the streams here may freeze the process if a child thread is + // performing file stream operations at the same time. + REAL(fflush)(stdout); + REAL(fflush)(stderr); +} + +TSAN_INTERCEPTOR(void, abort, int fake) { + SCOPED_TSAN_INTERCEPTOR(abort, fake); + FlushStreams(); + REAL(abort)(fake); +} + +TSAN_INTERCEPTOR(int, rmdir, char *path) { + SCOPED_TSAN_INTERCEPTOR(rmdir, path); + Release(thr, pc, Dir2addr(path)); + int res = REAL(rmdir)(path); + return res; +} + +TSAN_INTERCEPTOR(int, closedir, void *dirp) { + SCOPED_TSAN_INTERCEPTOR(closedir, dirp); + if (dirp) { + int fd = dirfd(dirp); + FdClose(thr, pc, fd); + } + return REAL(closedir)(dirp); +} + +#if SANITIZER_LINUX +TSAN_INTERCEPTOR(int, epoll_create, int size) { + SCOPED_TSAN_INTERCEPTOR(epoll_create, size); + int fd = REAL(epoll_create)(size); + if (fd >= 0) + FdPollCreate(thr, pc, fd); + return fd; +} + +TSAN_INTERCEPTOR(int, epoll_create1, int flags) { + SCOPED_TSAN_INTERCEPTOR(epoll_create1, flags); + int fd = REAL(epoll_create1)(flags); + if (fd >= 0) + FdPollCreate(thr, pc, fd); + return fd; +} + +TSAN_INTERCEPTOR(int, epoll_ctl, int epfd, int op, int fd, void *ev) { + SCOPED_TSAN_INTERCEPTOR(epoll_ctl, epfd, op, fd, ev); + if (epfd >= 0) + FdAccess(thr, pc, epfd); + if (epfd >= 0 && fd >= 0) + FdAccess(thr, pc, fd); + if (op == EPOLL_CTL_ADD && epfd >= 0) + FdRelease(thr, pc, epfd); + int res = REAL(epoll_ctl)(epfd, op, fd, ev); + return res; +} + +TSAN_INTERCEPTOR(int, epoll_wait, int epfd, void *ev, int cnt, int timeout) { + SCOPED_TSAN_INTERCEPTOR(epoll_wait, epfd, ev, cnt, timeout); + if (epfd >= 0) + FdAccess(thr, pc, epfd); + int res = BLOCK_REAL(epoll_wait)(epfd, ev, cnt, timeout); + if (res > 0 && epfd >= 0) + FdAcquire(thr, pc, epfd); + return res; +} + +TSAN_INTERCEPTOR(int, epoll_pwait, int epfd, void *ev, int cnt, int timeout, + void *sigmask) { + SCOPED_TSAN_INTERCEPTOR(epoll_pwait, epfd, ev, cnt, timeout, sigmask); + if (epfd >= 0) + FdAccess(thr, pc, epfd); + int res = BLOCK_REAL(epoll_pwait)(epfd, ev, cnt, timeout, sigmask); + if (res > 0 && epfd >= 0) + FdAcquire(thr, pc, epfd); + return res; +} + +#define TSAN_MAYBE_INTERCEPT_EPOLL \ + TSAN_INTERCEPT(epoll_create); \ + TSAN_INTERCEPT(epoll_create1); \ + TSAN_INTERCEPT(epoll_ctl); \ + TSAN_INTERCEPT(epoll_wait); \ + TSAN_INTERCEPT(epoll_pwait) +#else +#define TSAN_MAYBE_INTERCEPT_EPOLL +#endif + +// The following functions are intercepted merely to process pending signals. +// If program blocks signal X, we must deliver the signal before the function +// returns. Similarly, if program unblocks a signal (or returns from sigsuspend) +// it's better to deliver the signal straight away. +TSAN_INTERCEPTOR(int, sigsuspend, const __sanitizer_sigset_t *mask) { + SCOPED_TSAN_INTERCEPTOR(sigsuspend, mask); + return REAL(sigsuspend)(mask); +} + +TSAN_INTERCEPTOR(int, sigblock, int mask) { + SCOPED_TSAN_INTERCEPTOR(sigblock, mask); + return REAL(sigblock)(mask); +} + +TSAN_INTERCEPTOR(int, sigsetmask, int mask) { + SCOPED_TSAN_INTERCEPTOR(sigsetmask, mask); + return REAL(sigsetmask)(mask); +} + +TSAN_INTERCEPTOR(int, pthread_sigmask, int how, const __sanitizer_sigset_t *set, + __sanitizer_sigset_t *oldset) { + SCOPED_TSAN_INTERCEPTOR(pthread_sigmask, how, set, oldset); + return REAL(pthread_sigmask)(how, set, oldset); +} + +namespace __tsan { + +static void CallUserSignalHandler(ThreadState *thr, bool sync, bool acquire, + bool sigact, int sig, + __sanitizer_siginfo *info, void *uctx) { + __sanitizer_sigaction *sigactions = interceptor_ctx()->sigactions; + if (acquire) + Acquire(thr, 0, (uptr)&sigactions[sig]); + // Signals are generally asynchronous, so if we receive a signals when + // ignores are enabled we should disable ignores. This is critical for sync + // and interceptors, because otherwise we can miss syncronization and report + // false races. + int ignore_reads_and_writes = thr->ignore_reads_and_writes; + int ignore_interceptors = thr->ignore_interceptors; + int ignore_sync = thr->ignore_sync; + if (!ctx->after_multithreaded_fork) { + thr->ignore_reads_and_writes = 0; + thr->fast_state.ClearIgnoreBit(); + thr->ignore_interceptors = 0; + thr->ignore_sync = 0; + } + // Ensure that the handler does not spoil errno. + const int saved_errno = errno; + errno = 99; + // This code races with sigaction. Be careful to not read sa_sigaction twice. + // Also need to remember pc for reporting before the call, + // because the handler can reset it. + volatile uptr pc = + sigact ? (uptr)sigactions[sig].sigaction : (uptr)sigactions[sig].handler; + if (pc != sig_dfl && pc != sig_ign) { + if (sigact) + ((__sanitizer_sigactionhandler_ptr)pc)(sig, info, uctx); + else + ((__sanitizer_sighandler_ptr)pc)(sig); + } + if (!ctx->after_multithreaded_fork) { + thr->ignore_reads_and_writes = ignore_reads_and_writes; + if (ignore_reads_and_writes) + thr->fast_state.SetIgnoreBit(); + thr->ignore_interceptors = ignore_interceptors; + thr->ignore_sync = ignore_sync; + } + // We do not detect errno spoiling for SIGTERM, + // because some SIGTERM handlers do spoil errno but reraise SIGTERM, + // tsan reports false positive in such case. + // It's difficult to properly detect this situation (reraise), + // because in async signal processing case (when handler is called directly + // from rtl_generic_sighandler) we have not yet received the reraised + // signal; and it looks too fragile to intercept all ways to reraise a signal. + if (flags()->report_bugs && !sync && sig != SIGTERM && errno != 99) { + VarSizeStackTrace stack; + // StackTrace::GetNestInstructionPc(pc) is used because return address is + // expected, OutputReport() will undo this. + ObtainCurrentStack(thr, StackTrace::GetNextInstructionPc(pc), &stack); + ThreadRegistryLock l(ctx->thread_registry); + ScopedReport rep(ReportTypeErrnoInSignal); + if (!IsFiredSuppression(ctx, ReportTypeErrnoInSignal, stack)) { + rep.AddStack(stack, true); + OutputReport(thr, rep); + } + } + errno = saved_errno; +} + +void ProcessPendingSignals(ThreadState *thr) { + ThreadSignalContext *sctx = SigCtx(thr); + if (sctx == 0 || + atomic_load(&sctx->have_pending_signals, memory_order_relaxed) == 0) + return; + atomic_store(&sctx->have_pending_signals, 0, memory_order_relaxed); + 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); + CHECK_EQ(res, 0); + for (int sig = 0; sig < kSigCount; sig++) { + SignalDesc *signal = &sctx->pending_signals[sig]; + if (signal->armed) { + signal->armed = false; + CallUserSignalHandler(thr, false, true, signal->sigaction, sig, + &signal->siginfo, &signal->ctx); + } + } + res = REAL(pthread_sigmask)(SIG_SETMASK, &sctx->oldset, 0); + CHECK_EQ(res, 0); + atomic_fetch_add(&thr->in_signal_handler, -1, memory_order_relaxed); +} + +} // namespace __tsan + +static bool is_sync_signal(ThreadSignalContext *sctx, int sig) { + return sig == SIGSEGV || sig == SIGBUS || sig == SIGILL || sig == SIGTRAP || + sig == SIGABRT || sig == SIGFPE || sig == SIGPIPE || sig == SIGSYS || + // If we are sending signal to ourselves, we must process it now. + (sctx && sig == sctx->int_signal_send); +} + +void ALWAYS_INLINE rtl_generic_sighandler(bool sigact, int sig, + __sanitizer_siginfo *info, + void *ctx) { + cur_thread_init(); + ThreadState *thr = cur_thread(); + ThreadSignalContext *sctx = SigCtx(thr); + if (sig < 0 || sig >= kSigCount) { + VPrintf(1, "ThreadSanitizer: ignoring signal %d\n", sig); + return; + } + // Don't mess with synchronous signals. + const bool sync = is_sync_signal(sctx, sig); + if (sync || + // If we are in blocking function, we can safely process it now + // (but check if we are in a recursive interceptor, + // i.e. pthread_join()->munmap()). + (sctx && atomic_load(&sctx->in_blocking_func, memory_order_relaxed))) { + atomic_fetch_add(&thr->in_signal_handler, 1, memory_order_relaxed); + if (sctx && atomic_load(&sctx->in_blocking_func, memory_order_relaxed)) { + atomic_store(&sctx->in_blocking_func, 0, memory_order_relaxed); + CallUserSignalHandler(thr, sync, true, sigact, sig, info, ctx); + atomic_store(&sctx->in_blocking_func, 1, memory_order_relaxed); + } else { + // Be very conservative with when we do acquire in this case. + // It's unsafe to do acquire in async handlers, because ThreadState + // can be in inconsistent state. + // SIGSYS looks relatively safe -- it's synchronous and can actually + // need some global state. + bool acq = (sig == SIGSYS); + CallUserSignalHandler(thr, sync, acq, sigact, sig, info, ctx); + } + atomic_fetch_add(&thr->in_signal_handler, -1, memory_order_relaxed); + return; + } + + if (sctx == 0) + return; + SignalDesc *signal = &sctx->pending_signals[sig]; + if (signal->armed == false) { + signal->armed = true; + signal->sigaction = sigact; + if (info) + internal_memcpy(&signal->siginfo, info, sizeof(*info)); + if (ctx) + internal_memcpy(&signal->ctx, ctx, sizeof(signal->ctx)); + atomic_store(&sctx->have_pending_signals, 1, memory_order_relaxed); + } +} + +static void rtl_sighandler(int sig) { + rtl_generic_sighandler(false, sig, 0, 0); +} + +static void rtl_sigaction(int sig, __sanitizer_siginfo *info, void *ctx) { + rtl_generic_sighandler(true, sig, info, ctx); +} + +TSAN_INTERCEPTOR(int, raise, int sig) { + SCOPED_TSAN_INTERCEPTOR(raise, sig); + ThreadSignalContext *sctx = SigCtx(thr); + CHECK_NE(sctx, 0); + int prev = sctx->int_signal_send; + sctx->int_signal_send = sig; + int res = REAL(raise)(sig); + CHECK_EQ(sctx->int_signal_send, sig); + sctx->int_signal_send = prev; + return res; +} + +TSAN_INTERCEPTOR(int, kill, int pid, int sig) { + SCOPED_TSAN_INTERCEPTOR(kill, pid, sig); + ThreadSignalContext *sctx = SigCtx(thr); + CHECK_NE(sctx, 0); + int prev = sctx->int_signal_send; + if (pid == (int)internal_getpid()) { + sctx->int_signal_send = sig; + } + int res = REAL(kill)(pid, sig); + if (pid == (int)internal_getpid()) { + CHECK_EQ(sctx->int_signal_send, sig); + sctx->int_signal_send = prev; + } + return res; +} + +TSAN_INTERCEPTOR(int, pthread_kill, void *tid, int sig) { + SCOPED_TSAN_INTERCEPTOR(pthread_kill, tid, sig); + ThreadSignalContext *sctx = SigCtx(thr); + CHECK_NE(sctx, 0); + int prev = sctx->int_signal_send; + if (tid == pthread_self()) { + sctx->int_signal_send = sig; + } + int res = REAL(pthread_kill)(tid, sig); + if (tid == pthread_self()) { + CHECK_EQ(sctx->int_signal_send, sig); + sctx->int_signal_send = prev; + } + return res; +} + +TSAN_INTERCEPTOR(int, gettimeofday, void *tv, void *tz) { + SCOPED_TSAN_INTERCEPTOR(gettimeofday, tv, tz); + // It's intercepted merely to process pending signals. + return REAL(gettimeofday)(tv, tz); +} + +TSAN_INTERCEPTOR(int, getaddrinfo, void *node, void *service, + void *hints, void *rv) { + SCOPED_TSAN_INTERCEPTOR(getaddrinfo, node, service, hints, rv); + // We miss atomic synchronization in getaddrinfo, + // and can report false race between malloc and free + // inside of getaddrinfo. So ignore memory accesses. + ThreadIgnoreBegin(thr, pc); + int res = REAL(getaddrinfo)(node, service, hints, rv); + ThreadIgnoreEnd(thr, pc); + return res; +} + +TSAN_INTERCEPTOR(int, fork, int fake) { + if (in_symbolizer()) + return REAL(fork)(fake); + SCOPED_INTERCEPTOR_RAW(fork, fake); + ForkBefore(thr, pc); + int pid; + { + // On OS X, REAL(fork) can call intercepted functions (OSSpinLockLock), and + // we'll assert in CheckNoLocks() unless we ignore interceptors. + ScopedIgnoreInterceptors ignore; + pid = REAL(fork)(fake); + } + if (pid == 0) { + // child + ForkChildAfter(thr, pc); + FdOnFork(thr, pc); + } else if (pid > 0) { + // parent + ForkParentAfter(thr, pc); + } else { + // error + ForkParentAfter(thr, pc); + } + return pid; +} + +TSAN_INTERCEPTOR(int, vfork, int fake) { + // Some programs (e.g. openjdk) call close for all file descriptors + // in the child process. Under tsan it leads to false positives, because + // address space is shared, so the parent process also thinks that + // the descriptors are closed (while they are actually not). + // This leads to false positives due to missed synchronization. + // Strictly saying this is undefined behavior, because vfork child is not + // allowed to call any functions other than exec/exit. But this is what + // openjdk does, so we want to handle it. + // We could disable interceptors in the child process. But it's not possible + // to simply intercept and wrap vfork, because vfork child is not allowed + // to return from the function that calls vfork, and that's exactly what + // we would do. So this would require some assembly trickery as well. + // Instead we simply turn vfork into fork. + return WRAP(fork)(fake); +} + +#if !SANITIZER_MAC && !SANITIZER_ANDROID +typedef int (*dl_iterate_phdr_cb_t)(__sanitizer_dl_phdr_info *info, SIZE_T size, + void *data); +struct dl_iterate_phdr_data { + ThreadState *thr; + uptr pc; + dl_iterate_phdr_cb_t cb; + void *data; +}; + +static bool IsAppNotRodata(uptr addr) { + return IsAppMem(addr) && *(u64*)MemToShadow(addr) != kShadowRodata; +} + +static int dl_iterate_phdr_cb(__sanitizer_dl_phdr_info *info, SIZE_T size, + void *data) { + dl_iterate_phdr_data *cbdata = (dl_iterate_phdr_data *)data; + // dlopen/dlclose allocate/free dynamic-linker-internal memory, which is later + // accessible in dl_iterate_phdr callback. But we don't see synchronization + // inside of dynamic linker, so we "unpoison" it here in order to not + // produce false reports. Ignoring malloc/free in dlopen/dlclose is not enough + // because some libc functions call __libc_dlopen. + if (info && IsAppNotRodata((uptr)info->dlpi_name)) + MemoryResetRange(cbdata->thr, cbdata->pc, (uptr)info->dlpi_name, + internal_strlen(info->dlpi_name)); + int res = cbdata->cb(info, size, cbdata->data); + // Perform the check one more time in case info->dlpi_name was overwritten + // by user callback. + if (info && IsAppNotRodata((uptr)info->dlpi_name)) + MemoryResetRange(cbdata->thr, cbdata->pc, (uptr)info->dlpi_name, + internal_strlen(info->dlpi_name)); + return res; +} + +TSAN_INTERCEPTOR(int, dl_iterate_phdr, dl_iterate_phdr_cb_t cb, void *data) { + SCOPED_TSAN_INTERCEPTOR(dl_iterate_phdr, cb, data); + dl_iterate_phdr_data cbdata; + cbdata.thr = thr; + cbdata.pc = pc; + cbdata.cb = cb; + cbdata.data = data; + int res = REAL(dl_iterate_phdr)(dl_iterate_phdr_cb, &cbdata); + return res; +} +#endif + +static int OnExit(ThreadState *thr) { + int status = Finalize(thr); + FlushStreams(); + return status; +} + +struct TsanInterceptorContext { + ThreadState *thr; + const uptr caller_pc; + const uptr pc; +}; + +#if !SANITIZER_MAC +static void HandleRecvmsg(ThreadState *thr, uptr pc, + __sanitizer_msghdr *msg) { + int fds[64]; + int cnt = ExtractRecvmsgFDs(msg, fds, ARRAY_SIZE(fds)); + for (int i = 0; i < cnt; i++) + FdEventCreate(thr, pc, fds[i]); +} +#endif + +#include "sanitizer_common/sanitizer_platform_interceptors.h" +// Causes interceptor recursion (getaddrinfo() and fopen()) +#undef SANITIZER_INTERCEPT_GETADDRINFO +// We define our own. +#if SANITIZER_INTERCEPT_TLS_GET_ADDR +#define NEED_TLS_GET_ADDR +#endif +#undef SANITIZER_INTERCEPT_TLS_GET_ADDR +#undef SANITIZER_INTERCEPT_PTHREAD_SIGMASK + +#define COMMON_INTERCEPT_FUNCTION(name) INTERCEPT_FUNCTION(name) +#define COMMON_INTERCEPT_FUNCTION_VER(name, ver) \ + INTERCEPT_FUNCTION_VER(name, ver) + +#define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \ + MemoryAccessRange(((TsanInterceptorContext *)ctx)->thr, \ + ((TsanInterceptorContext *)ctx)->pc, (uptr)ptr, size, \ + true) + +#define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \ + MemoryAccessRange(((TsanInterceptorContext *) ctx)->thr, \ + ((TsanInterceptorContext *) ctx)->pc, (uptr) ptr, size, \ + false) + +#define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \ + SCOPED_TSAN_INTERCEPTOR(func, __VA_ARGS__); \ + TsanInterceptorContext _ctx = {thr, caller_pc, pc}; \ + ctx = (void *)&_ctx; \ + (void) ctx; + +#define COMMON_INTERCEPTOR_ENTER_NOIGNORE(ctx, func, ...) \ + SCOPED_INTERCEPTOR_RAW(func, __VA_ARGS__); \ + TsanInterceptorContext _ctx = {thr, caller_pc, pc}; \ + ctx = (void *)&_ctx; \ + (void) ctx; + +#define COMMON_INTERCEPTOR_FILE_OPEN(ctx, file, path) \ + if (path) \ + Acquire(thr, pc, File2addr(path)); \ + if (file) { \ + int fd = fileno_unlocked(file); \ + if (fd >= 0) FdFileCreate(thr, pc, fd); \ + } + +#define COMMON_INTERCEPTOR_FILE_CLOSE(ctx, file) \ + if (file) { \ + int fd = fileno_unlocked(file); \ + if (fd >= 0) FdClose(thr, pc, fd); \ + } + +#define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, handle) \ + libignore()->OnLibraryLoaded(filename) + +#define COMMON_INTERCEPTOR_LIBRARY_UNLOADED() \ + libignore()->OnLibraryUnloaded() + +#define COMMON_INTERCEPTOR_ACQUIRE(ctx, u) \ + Acquire(((TsanInterceptorContext *) ctx)->thr, pc, u) + +#define COMMON_INTERCEPTOR_RELEASE(ctx, u) \ + Release(((TsanInterceptorContext *) ctx)->thr, pc, u) + +#define COMMON_INTERCEPTOR_DIR_ACQUIRE(ctx, path) \ + Acquire(((TsanInterceptorContext *) ctx)->thr, pc, Dir2addr(path)) + +#define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) \ + FdAcquire(((TsanInterceptorContext *) ctx)->thr, pc, fd) + +#define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) \ + FdRelease(((TsanInterceptorContext *) ctx)->thr, pc, fd) + +#define COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd) \ + FdAccess(((TsanInterceptorContext *) ctx)->thr, pc, fd) + +#define COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, newfd) \ + FdSocketAccept(((TsanInterceptorContext *) ctx)->thr, pc, fd, newfd) + +#define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name) \ + ThreadSetName(((TsanInterceptorContext *) ctx)->thr, name) + +#define COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name) \ + __tsan::ctx->thread_registry->SetThreadNameByUserId(thread, name) + +#define COMMON_INTERCEPTOR_BLOCK_REAL(name) BLOCK_REAL(name) + +#define COMMON_INTERCEPTOR_ON_EXIT(ctx) \ + OnExit(((TsanInterceptorContext *) ctx)->thr) + +#define COMMON_INTERCEPTOR_MUTEX_PRE_LOCK(ctx, m) \ + MutexPreLock(((TsanInterceptorContext *)ctx)->thr, \ + ((TsanInterceptorContext *)ctx)->pc, (uptr)m) + +#define COMMON_INTERCEPTOR_MUTEX_POST_LOCK(ctx, m) \ + MutexPostLock(((TsanInterceptorContext *)ctx)->thr, \ + ((TsanInterceptorContext *)ctx)->pc, (uptr)m) + +#define COMMON_INTERCEPTOR_MUTEX_UNLOCK(ctx, m) \ + MutexUnlock(((TsanInterceptorContext *)ctx)->thr, \ + ((TsanInterceptorContext *)ctx)->pc, (uptr)m) + +#define COMMON_INTERCEPTOR_MUTEX_REPAIR(ctx, m) \ + MutexRepair(((TsanInterceptorContext *)ctx)->thr, \ + ((TsanInterceptorContext *)ctx)->pc, (uptr)m) + +#define COMMON_INTERCEPTOR_MUTEX_INVALID(ctx, m) \ + MutexInvalidAccess(((TsanInterceptorContext *)ctx)->thr, \ + ((TsanInterceptorContext *)ctx)->pc, (uptr)m) + +#define COMMON_INTERCEPTOR_MMAP_IMPL(ctx, mmap, addr, sz, prot, flags, fd, \ + off) \ + do { \ + return mmap_interceptor(thr, pc, REAL(mmap), addr, sz, prot, flags, fd, \ + off); \ + } while (false) + +#if !SANITIZER_MAC +#define COMMON_INTERCEPTOR_HANDLE_RECVMSG(ctx, msg) \ + HandleRecvmsg(((TsanInterceptorContext *)ctx)->thr, \ + ((TsanInterceptorContext *)ctx)->pc, msg) +#endif + +#define COMMON_INTERCEPTOR_GET_TLS_RANGE(begin, end) \ + if (TsanThread *t = GetCurrentThread()) { \ + *begin = t->tls_begin(); \ + *end = t->tls_end(); \ + } else { \ + *begin = *end = 0; \ + } + +#define COMMON_INTERCEPTOR_USER_CALLBACK_START() \ + SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START() + +#define COMMON_INTERCEPTOR_USER_CALLBACK_END() \ + SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END() + +#include "sanitizer_common/sanitizer_common_interceptors.inc" + +static int sigaction_impl(int sig, const __sanitizer_sigaction *act, + __sanitizer_sigaction *old); +static __sanitizer_sighandler_ptr signal_impl(int sig, + __sanitizer_sighandler_ptr h); + +#define SIGNAL_INTERCEPTOR_SIGACTION_IMPL(signo, act, oldact) \ + { return sigaction_impl(signo, act, oldact); } + +#define SIGNAL_INTERCEPTOR_SIGNAL_IMPL(func, signo, handler) \ + { return (uptr)signal_impl(signo, (__sanitizer_sighandler_ptr)handler); } + +#include "sanitizer_common/sanitizer_signal_interceptors.inc" + +int sigaction_impl(int sig, const __sanitizer_sigaction *act, + __sanitizer_sigaction *old) { + // Note: if we call REAL(sigaction) directly for any reason without proxying + // the signal handler through rtl_sigaction, very bad things will happen. + // The handler will run synchronously and corrupt tsan per-thread state. + SCOPED_INTERCEPTOR_RAW(sigaction, sig, act, old); + __sanitizer_sigaction *sigactions = interceptor_ctx()->sigactions; + __sanitizer_sigaction old_stored; + if (old) internal_memcpy(&old_stored, &sigactions[sig], sizeof(old_stored)); + __sanitizer_sigaction newact; + if (act) { + // Copy act into sigactions[sig]. + // Can't use struct copy, because compiler can emit call to memcpy. + // Can't use internal_memcpy, because it copies byte-by-byte, + // and signal handler reads the handler concurrently. It it can read + // some bytes from old value and some bytes from new value. + // Use volatile to prevent insertion of memcpy. + sigactions[sig].handler = + *(volatile __sanitizer_sighandler_ptr const *)&act->handler; + sigactions[sig].sa_flags = *(volatile int const *)&act->sa_flags; + internal_memcpy(&sigactions[sig].sa_mask, &act->sa_mask, + sizeof(sigactions[sig].sa_mask)); +#if !SANITIZER_FREEBSD && !SANITIZER_MAC && !SANITIZER_NETBSD + sigactions[sig].sa_restorer = act->sa_restorer; +#endif + internal_memcpy(&newact, act, sizeof(newact)); + internal_sigfillset(&newact.sa_mask); + if ((uptr)act->handler != sig_ign && (uptr)act->handler != sig_dfl) { + if (newact.sa_flags & SA_SIGINFO) + newact.sigaction = rtl_sigaction; + else + newact.handler = rtl_sighandler; + } + ReleaseStore(thr, pc, (uptr)&sigactions[sig]); + act = &newact; + } + int res = REAL(sigaction)(sig, act, old); + if (res == 0 && old) { + uptr cb = (uptr)old->sigaction; + if (cb == (uptr)rtl_sigaction || cb == (uptr)rtl_sighandler) { + internal_memcpy(old, &old_stored, sizeof(*old)); + } + } + return res; +} + +static __sanitizer_sighandler_ptr signal_impl(int sig, + __sanitizer_sighandler_ptr h) { + __sanitizer_sigaction act; + act.handler = h; + internal_memset(&act.sa_mask, -1, sizeof(act.sa_mask)); + act.sa_flags = 0; + __sanitizer_sigaction old; + int res = sigaction_symname(sig, &act, &old); + if (res) return (__sanitizer_sighandler_ptr)sig_err; + return old.handler; +} + +#define TSAN_SYSCALL() \ + ThreadState *thr = cur_thread(); \ + if (thr->ignore_interceptors) \ + return; \ + ScopedSyscall scoped_syscall(thr) \ +/**/ + +struct ScopedSyscall { + ThreadState *thr; + + explicit ScopedSyscall(ThreadState *thr) + : thr(thr) { + Initialize(thr); + } + + ~ScopedSyscall() { + ProcessPendingSignals(thr); + } +}; + +#if !SANITIZER_FREEBSD && !SANITIZER_MAC +static void syscall_access_range(uptr pc, uptr p, uptr s, bool write) { + TSAN_SYSCALL(); + MemoryAccessRange(thr, pc, p, s, write); +} + +static void syscall_acquire(uptr pc, uptr addr) { + TSAN_SYSCALL(); + Acquire(thr, pc, addr); + DPrintf("syscall_acquire(%p)\n", addr); +} + +static void syscall_release(uptr pc, uptr addr) { + TSAN_SYSCALL(); + DPrintf("syscall_release(%p)\n", addr); + Release(thr, pc, addr); +} + +static void syscall_fd_close(uptr pc, int fd) { + TSAN_SYSCALL(); + FdClose(thr, pc, fd); +} + +static USED void syscall_fd_acquire(uptr pc, int fd) { + TSAN_SYSCALL(); + FdAcquire(thr, pc, fd); + DPrintf("syscall_fd_acquire(%p)\n", fd); +} + +static USED void syscall_fd_release(uptr pc, int fd) { + TSAN_SYSCALL(); + DPrintf("syscall_fd_release(%p)\n", fd); + FdRelease(thr, pc, fd); +} + +static void syscall_pre_fork(uptr pc) { + TSAN_SYSCALL(); + ForkBefore(thr, pc); +} + +static void syscall_post_fork(uptr pc, int pid) { + TSAN_SYSCALL(); + if (pid == 0) { + // child + ForkChildAfter(thr, pc); + FdOnFork(thr, pc); + } else if (pid > 0) { + // parent + ForkParentAfter(thr, pc); + } else { + // error + ForkParentAfter(thr, pc); + } +} +#endif + +#define COMMON_SYSCALL_PRE_READ_RANGE(p, s) \ + syscall_access_range(GET_CALLER_PC(), (uptr)(p), (uptr)(s), false) + +#define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) \ + syscall_access_range(GET_CALLER_PC(), (uptr)(p), (uptr)(s), true) + +#define COMMON_SYSCALL_POST_READ_RANGE(p, s) \ + do { \ + (void)(p); \ + (void)(s); \ + } while (false) + +#define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) \ + do { \ + (void)(p); \ + (void)(s); \ + } while (false) + +#define COMMON_SYSCALL_ACQUIRE(addr) \ + syscall_acquire(GET_CALLER_PC(), (uptr)(addr)) + +#define COMMON_SYSCALL_RELEASE(addr) \ + syscall_release(GET_CALLER_PC(), (uptr)(addr)) + +#define COMMON_SYSCALL_FD_CLOSE(fd) syscall_fd_close(GET_CALLER_PC(), fd) + +#define COMMON_SYSCALL_FD_ACQUIRE(fd) syscall_fd_acquire(GET_CALLER_PC(), fd) + +#define COMMON_SYSCALL_FD_RELEASE(fd) syscall_fd_release(GET_CALLER_PC(), fd) + +#define COMMON_SYSCALL_PRE_FORK() \ + syscall_pre_fork(GET_CALLER_PC()) + +#define COMMON_SYSCALL_POST_FORK(res) \ + syscall_post_fork(GET_CALLER_PC(), res) + +#include "sanitizer_common/sanitizer_common_syscalls.inc" +#include "sanitizer_common/sanitizer_syscalls_netbsd.inc" + +#ifdef NEED_TLS_GET_ADDR +// Define own interceptor instead of sanitizer_common's for three reasons: +// 1. It must not process pending signals. +// Signal handlers may contain MOVDQA instruction (see below). +// 2. It must be as simple as possible to not contain MOVDQA. +// 3. Sanitizer_common version uses COMMON_INTERCEPTOR_INITIALIZE_RANGE which +// is empty for tsan (meant only for msan). +// Note: __tls_get_addr can be called with mis-aligned stack due to: +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58066 +// So the interceptor must work with mis-aligned stack, in particular, does not +// execute MOVDQA with stack addresses. +TSAN_INTERCEPTOR(void *, __tls_get_addr, void *arg) { + void *res = REAL(__tls_get_addr)(arg); + ThreadState *thr = cur_thread(); + if (!thr) + return res; + DTLS::DTV *dtv = DTLS_on_tls_get_addr(arg, res, thr->tls_addr, + thr->tls_addr + thr->tls_size); + if (!dtv) + return res; + // New DTLS block has been allocated. + MemoryResetRange(thr, 0, dtv->beg, dtv->size); + return res; +} +#endif + +#if SANITIZER_NETBSD +TSAN_INTERCEPTOR(void, _lwp_exit) { + SCOPED_TSAN_INTERCEPTOR(_lwp_exit); + DestroyThreadState(); + REAL(_lwp_exit)(); +} +#define TSAN_MAYBE_INTERCEPT__LWP_EXIT TSAN_INTERCEPT(_lwp_exit) +#else +#define TSAN_MAYBE_INTERCEPT__LWP_EXIT +#endif + +#if SANITIZER_FREEBSD +TSAN_INTERCEPTOR(void, thr_exit, tid_t *state) { + SCOPED_TSAN_INTERCEPTOR(thr_exit, state); + DestroyThreadState(); + REAL(thr_exit(state)); +} +#define TSAN_MAYBE_INTERCEPT_THR_EXIT TSAN_INTERCEPT(thr_exit) +#else +#define TSAN_MAYBE_INTERCEPT_THR_EXIT +#endif + +TSAN_INTERCEPTOR_NETBSD_ALIAS(int, cond_init, void *c, void *a) +TSAN_INTERCEPTOR_NETBSD_ALIAS(int, cond_signal, void *c) +TSAN_INTERCEPTOR_NETBSD_ALIAS(int, cond_broadcast, void *c) +TSAN_INTERCEPTOR_NETBSD_ALIAS(int, cond_wait, void *c, void *m) +TSAN_INTERCEPTOR_NETBSD_ALIAS(int, cond_destroy, void *c) +TSAN_INTERCEPTOR_NETBSD_ALIAS(int, mutex_init, void *m, void *a) +TSAN_INTERCEPTOR_NETBSD_ALIAS(int, mutex_destroy, void *m) +TSAN_INTERCEPTOR_NETBSD_ALIAS(int, mutex_trylock, void *m) +TSAN_INTERCEPTOR_NETBSD_ALIAS(int, rwlock_init, void *m, void *a) +TSAN_INTERCEPTOR_NETBSD_ALIAS(int, rwlock_destroy, void *m) +TSAN_INTERCEPTOR_NETBSD_ALIAS(int, rwlock_rdlock, void *m) +TSAN_INTERCEPTOR_NETBSD_ALIAS(int, rwlock_tryrdlock, void *m) +TSAN_INTERCEPTOR_NETBSD_ALIAS(int, rwlock_wrlock, void *m) +TSAN_INTERCEPTOR_NETBSD_ALIAS(int, rwlock_trywrlock, void *m) +TSAN_INTERCEPTOR_NETBSD_ALIAS(int, rwlock_unlock, void *m) +TSAN_INTERCEPTOR_NETBSD_ALIAS_THR(int, once, void *o, void (*f)()) +TSAN_INTERCEPTOR_NETBSD_ALIAS_THR2(int, sigsetmask, sigmask, int a, void *b, + void *c) + +namespace __tsan { + +static void finalize(void *arg) { + ThreadState *thr = cur_thread(); + int status = Finalize(thr); + // Make sure the output is not lost. + FlushStreams(); + if (status) + Die(); +} + +#if !SANITIZER_MAC && !SANITIZER_ANDROID +static void unreachable() { + Report("FATAL: ThreadSanitizer: unreachable called\n"); + Die(); +} +#endif + +// Define default implementation since interception of libdispatch is optional. +SANITIZER_WEAK_ATTRIBUTE void InitializeLibdispatchInterceptors() {} + +void InitializeInterceptors() { +#if !SANITIZER_MAC + // We need to setup it early, because functions like dlsym() can call it. + REAL(memset) = internal_memset; + REAL(memcpy) = internal_memcpy; +#endif + + // Instruct libc malloc to consume less memory. +#if SANITIZER_LINUX + mallopt(1, 0); // M_MXFAST + mallopt(-3, 32*1024); // M_MMAP_THRESHOLD +#endif + + new(interceptor_ctx()) InterceptorContext(); + + InitializeCommonInterceptors(); + InitializeSignalInterceptors(); + InitializeLibdispatchInterceptors(); + +#if !SANITIZER_MAC + // We can not use TSAN_INTERCEPT to get setjmp addr, + // because it does &setjmp and setjmp is not present in some versions of libc. + using __interception::InterceptFunction; + InterceptFunction(TSAN_STRING_SETJMP, (uptr*)&REAL(setjmp_symname), 0, 0); + InterceptFunction("_setjmp", (uptr*)&REAL(_setjmp), 0, 0); + InterceptFunction(TSAN_STRING_SIGSETJMP, (uptr*)&REAL(sigsetjmp_symname), 0, + 0); +#if !SANITIZER_NETBSD + InterceptFunction("__sigsetjmp", (uptr*)&REAL(__sigsetjmp), 0, 0); +#endif +#endif + + TSAN_INTERCEPT(longjmp_symname); + TSAN_INTERCEPT(siglongjmp_symname); +#if SANITIZER_NETBSD + TSAN_INTERCEPT(_longjmp); +#endif + + TSAN_INTERCEPT(malloc); + TSAN_INTERCEPT(__libc_memalign); + TSAN_INTERCEPT(calloc); + TSAN_INTERCEPT(realloc); + TSAN_INTERCEPT(reallocarray); + TSAN_INTERCEPT(free); + TSAN_INTERCEPT(cfree); + TSAN_INTERCEPT(munmap); + TSAN_MAYBE_INTERCEPT_MEMALIGN; + TSAN_INTERCEPT(valloc); + TSAN_MAYBE_INTERCEPT_PVALLOC; + TSAN_INTERCEPT(posix_memalign); + + TSAN_INTERCEPT(strcpy); + TSAN_INTERCEPT(strncpy); + TSAN_INTERCEPT(strdup); + + TSAN_INTERCEPT(pthread_create); + TSAN_INTERCEPT(pthread_join); + TSAN_INTERCEPT(pthread_detach); + TSAN_INTERCEPT(pthread_exit); + #if SANITIZER_LINUX + TSAN_INTERCEPT(pthread_tryjoin_np); + TSAN_INTERCEPT(pthread_timedjoin_np); + #endif + + TSAN_INTERCEPT_VER(pthread_cond_init, PTHREAD_ABI_BASE); + TSAN_INTERCEPT_VER(pthread_cond_signal, PTHREAD_ABI_BASE); + TSAN_INTERCEPT_VER(pthread_cond_broadcast, PTHREAD_ABI_BASE); + TSAN_INTERCEPT_VER(pthread_cond_wait, PTHREAD_ABI_BASE); + TSAN_INTERCEPT_VER(pthread_cond_timedwait, PTHREAD_ABI_BASE); + TSAN_INTERCEPT_VER(pthread_cond_destroy, PTHREAD_ABI_BASE); + + TSAN_INTERCEPT(pthread_mutex_init); + TSAN_INTERCEPT(pthread_mutex_destroy); + TSAN_INTERCEPT(pthread_mutex_trylock); + TSAN_INTERCEPT(pthread_mutex_timedlock); + + TSAN_INTERCEPT(pthread_spin_init); + TSAN_INTERCEPT(pthread_spin_destroy); + TSAN_INTERCEPT(pthread_spin_lock); + TSAN_INTERCEPT(pthread_spin_trylock); + TSAN_INTERCEPT(pthread_spin_unlock); + + TSAN_INTERCEPT(pthread_rwlock_init); + TSAN_INTERCEPT(pthread_rwlock_destroy); + TSAN_INTERCEPT(pthread_rwlock_rdlock); + TSAN_INTERCEPT(pthread_rwlock_tryrdlock); + TSAN_INTERCEPT(pthread_rwlock_timedrdlock); + TSAN_INTERCEPT(pthread_rwlock_wrlock); + TSAN_INTERCEPT(pthread_rwlock_trywrlock); + TSAN_INTERCEPT(pthread_rwlock_timedwrlock); + TSAN_INTERCEPT(pthread_rwlock_unlock); + + TSAN_INTERCEPT(pthread_barrier_init); + TSAN_INTERCEPT(pthread_barrier_destroy); + TSAN_INTERCEPT(pthread_barrier_wait); + + TSAN_INTERCEPT(pthread_once); + + TSAN_INTERCEPT(fstat); + TSAN_MAYBE_INTERCEPT___FXSTAT; + TSAN_MAYBE_INTERCEPT_FSTAT64; + TSAN_MAYBE_INTERCEPT___FXSTAT64; + TSAN_INTERCEPT(open); + TSAN_MAYBE_INTERCEPT_OPEN64; + TSAN_INTERCEPT(creat); + TSAN_MAYBE_INTERCEPT_CREAT64; + TSAN_INTERCEPT(dup); + TSAN_INTERCEPT(dup2); + TSAN_INTERCEPT(dup3); + TSAN_MAYBE_INTERCEPT_EVENTFD; + TSAN_MAYBE_INTERCEPT_SIGNALFD; + TSAN_MAYBE_INTERCEPT_INOTIFY_INIT; + TSAN_MAYBE_INTERCEPT_INOTIFY_INIT1; + TSAN_INTERCEPT(socket); + TSAN_INTERCEPT(socketpair); + TSAN_INTERCEPT(connect); + TSAN_INTERCEPT(bind); + TSAN_INTERCEPT(listen); + TSAN_MAYBE_INTERCEPT_EPOLL; + TSAN_INTERCEPT(close); + TSAN_MAYBE_INTERCEPT___CLOSE; + TSAN_MAYBE_INTERCEPT___RES_ICLOSE; + TSAN_INTERCEPT(pipe); + TSAN_INTERCEPT(pipe2); + + TSAN_INTERCEPT(unlink); + TSAN_INTERCEPT(tmpfile); + TSAN_MAYBE_INTERCEPT_TMPFILE64; + TSAN_INTERCEPT(abort); + TSAN_INTERCEPT(rmdir); + TSAN_INTERCEPT(closedir); + + TSAN_INTERCEPT(sigsuspend); + TSAN_INTERCEPT(sigblock); + TSAN_INTERCEPT(sigsetmask); + TSAN_INTERCEPT(pthread_sigmask); + TSAN_INTERCEPT(raise); + TSAN_INTERCEPT(kill); + TSAN_INTERCEPT(pthread_kill); + TSAN_INTERCEPT(sleep); + TSAN_INTERCEPT(usleep); + TSAN_INTERCEPT(nanosleep); + TSAN_INTERCEPT(pause); + TSAN_INTERCEPT(gettimeofday); + TSAN_INTERCEPT(getaddrinfo); + + TSAN_INTERCEPT(fork); + TSAN_INTERCEPT(vfork); +#if !SANITIZER_ANDROID + TSAN_INTERCEPT(dl_iterate_phdr); +#endif + TSAN_MAYBE_INTERCEPT_ON_EXIT; + TSAN_INTERCEPT(__cxa_atexit); + TSAN_INTERCEPT(_exit); + +#ifdef NEED_TLS_GET_ADDR + TSAN_INTERCEPT(__tls_get_addr); +#endif + + TSAN_MAYBE_INTERCEPT__LWP_EXIT; + TSAN_MAYBE_INTERCEPT_THR_EXIT; + +#if !SANITIZER_MAC && !SANITIZER_ANDROID + // Need to setup it, because interceptors check that the function is resolved. + // But atexit is emitted directly into the module, so can't be resolved. + REAL(atexit) = (int(*)(void(*)()))unreachable; +#endif + + if (REAL(__cxa_atexit)(&finalize, 0, 0)) { + Printf("ThreadSanitizer: failed to setup atexit callback\n"); + Die(); + } + +#if !SANITIZER_MAC && !SANITIZER_NETBSD && !SANITIZER_FREEBSD + if (pthread_key_create(&interceptor_ctx()->finalize_key, &thread_finalize)) { + Printf("ThreadSanitizer: failed to create thread key\n"); + Die(); + } +#endif + + TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(cond_init); + TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(cond_signal); + TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(cond_broadcast); + TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(cond_wait); + TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(cond_destroy); + TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(mutex_init); + TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(mutex_destroy); + TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(mutex_trylock); + TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(rwlock_init); + TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(rwlock_destroy); + TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(rwlock_rdlock); + TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(rwlock_tryrdlock); + TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(rwlock_wrlock); + TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(rwlock_trywrlock); + TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(rwlock_unlock); + TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS_THR(once); + TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS_THR(sigsetmask); + + FdInit(); +} + +} // namespace __tsan + +// Invisible barrier for tests. +// There were several unsuccessful iterations for this functionality: +// 1. Initially it was implemented in user code using +// REAL(pthread_barrier_wait). But pthread_barrier_wait is not supported on +// MacOS. Futexes are linux-specific for this matter. +// 2. Then we switched to atomics+usleep(10). But usleep produced parasitic +// "as-if synchronized via sleep" messages in reports which failed some +// output tests. +// 3. Then we switched to atomics+sched_yield. But this produced tons of tsan- +// visible events, which lead to "failed to restore stack trace" failures. +// Note that no_sanitize_thread attribute does not turn off atomic interception +// so attaching it to the function defined in user code does not help. +// That's why we now have what we have. +extern "C" SANITIZER_INTERFACE_ATTRIBUTE +void __tsan_testonly_barrier_init(u64 *barrier, u32 count) { + if (count >= (1 << 8)) { + Printf("barrier_init: count is too large (%d)\n", count); + Die(); + } + // 8 lsb is thread count, the remaining are count of entered threads. + *barrier = count; +} + +extern "C" SANITIZER_INTERFACE_ATTRIBUTE +void __tsan_testonly_barrier_wait(u64 *barrier) { + unsigned old = __atomic_fetch_add(barrier, 1 << 8, __ATOMIC_RELAXED); + unsigned old_epoch = (old >> 8) / (old & 0xff); + for (;;) { + unsigned cur = __atomic_load_n(barrier, __ATOMIC_RELAXED); + unsigned cur_epoch = (cur >> 8) / (cur & 0xff); + if (cur_epoch != old_epoch) + return; + internal_sched_yield(); + } +} diff --git a/libsanitizer/tsan/tsan_interface.cpp b/libsanitizer/tsan/tsan_interface.cpp index 845d8c8520c..2b3a0889b70 100644 --- a/libsanitizer/tsan/tsan_interface.cpp +++ b/libsanitizer/tsan/tsan_interface.cpp @@ -17,7 +17,7 @@ #define CALLERPC ((uptr)__builtin_return_address(0)) -using namespace __tsan; // NOLINT +using namespace __tsan; typedef u16 uint16_t; typedef u32 uint32_t; diff --git a/libsanitizer/tsan/tsan_interface.h b/libsanitizer/tsan/tsan_interface.h index fac57809aa2..6d7286ca5b8 100644 --- a/libsanitizer/tsan/tsan_interface.h +++ b/libsanitizer/tsan/tsan_interface.h @@ -90,9 +90,14 @@ SANITIZER_INTERFACE_ATTRIBUTE void __tsan_external_write(void *addr, void *caller_pc, void *tag); SANITIZER_INTERFACE_ATTRIBUTE -void __tsan_read_range(void *addr, unsigned long size); // NOLINT +void __tsan_read_range(void *addr, unsigned long size); SANITIZER_INTERFACE_ATTRIBUTE -void __tsan_write_range(void *addr, unsigned long size); // NOLINT +void __tsan_write_range(void *addr, unsigned long size); + +SANITIZER_INTERFACE_ATTRIBUTE +void __tsan_read_range_pc(void *addr, unsigned long size, void *pc); // NOLINT +SANITIZER_INTERFACE_ATTRIBUTE +void __tsan_write_range_pc(void *addr, unsigned long size, void *pc); // NOLINT // User may provide function that would be called right when TSan detects // an error. The argument 'report' is an opaque pointer that can be used to @@ -187,9 +192,9 @@ namespace __tsan { // These should match declarations from public tsan_interface_atomic.h header. typedef unsigned char a8; -typedef unsigned short a16; // NOLINT +typedef unsigned short a16; typedef unsigned int a32; -typedef unsigned long long a64; // NOLINT +typedef unsigned long long a64; #if !SANITIZER_GO && (defined(__SIZEOF_INT128__) \ || (__clang_major__ * 100 + __clang_minor__ >= 302)) && !defined(__mips64) __extension__ typedef __int128 a128; diff --git a/libsanitizer/tsan/tsan_interface_ann.cpp b/libsanitizer/tsan/tsan_interface_ann.cpp index 288485c17fa..99516d94bba 100644 --- a/libsanitizer/tsan/tsan_interface_ann.cpp +++ b/libsanitizer/tsan/tsan_interface_ann.cpp @@ -24,7 +24,7 @@ #define CALLERPC ((uptr)__builtin_return_address(0)) -using namespace __tsan; // NOLINT +using namespace __tsan; namespace __tsan { @@ -220,7 +220,7 @@ static void ReportMissedExpectedRace(ExpectRace *race) { } } // namespace __tsan -using namespace __tsan; // NOLINT +using namespace __tsan; extern "C" { void INTERFACE_ATTRIBUTE AnnotateHappensBefore(char *f, int l, uptr addr) { diff --git a/libsanitizer/tsan/tsan_interface_atomic.cpp b/libsanitizer/tsan/tsan_interface_atomic.cpp index 730a8e63f74..3f459aff532 100644 --- a/libsanitizer/tsan/tsan_interface_atomic.cpp +++ b/libsanitizer/tsan/tsan_interface_atomic.cpp @@ -25,7 +25,7 @@ #include "tsan_interface.h" #include "tsan_rtl.h" -using namespace __tsan; // NOLINT +using namespace __tsan; #if !SANITIZER_GO && __TSAN_HAS_INT128 // Protects emulation of 128-bit atomic operations. diff --git a/libsanitizer/tsan/tsan_interface_inl.h b/libsanitizer/tsan/tsan_interface_inl.h index bf4a1658625..f955ddf9924 100644 --- a/libsanitizer/tsan/tsan_interface_inl.h +++ b/libsanitizer/tsan/tsan_interface_inl.h @@ -15,7 +15,7 @@ #define CALLERPC ((uptr)__builtin_return_address(0)) -using namespace __tsan; // NOLINT +using namespace __tsan; void __tsan_read1(void *addr) { MemoryRead(cur_thread(), CALLERPC, (uptr)addr, kSizeLog1); @@ -122,3 +122,11 @@ void __tsan_read_range(void *addr, uptr size) { void __tsan_write_range(void *addr, uptr size) { MemoryAccessRange(cur_thread(), CALLERPC, (uptr)addr, size, true); } + +void __tsan_read_range_pc(void *addr, uptr size, void *pc) { + MemoryAccessRange(cur_thread(), (uptr)pc, (uptr)addr, size, false); +} + +void __tsan_write_range_pc(void *addr, uptr size, void *pc) { + MemoryAccessRange(cur_thread(), (uptr)pc, (uptr)addr, size, true); +} diff --git a/libsanitizer/tsan/tsan_interface_java.cpp b/libsanitizer/tsan/tsan_interface_java.cpp index 7d3d32fdbe0..081c6ff1022 100644 --- a/libsanitizer/tsan/tsan_interface_java.cpp +++ b/libsanitizer/tsan/tsan_interface_java.cpp @@ -19,7 +19,7 @@ #include "sanitizer_common/sanitizer_stacktrace.h" #include "sanitizer_common/sanitizer_procmaps.h" -using namespace __tsan; // NOLINT +using namespace __tsan; const jptr kHeapAlignment = 8; diff --git a/libsanitizer/tsan/tsan_interface_java.h b/libsanitizer/tsan/tsan_interface_java.h index 93e67bd10b1..51b445251e0 100644 --- a/libsanitizer/tsan/tsan_interface_java.h +++ b/libsanitizer/tsan/tsan_interface_java.h @@ -31,7 +31,7 @@ extern "C" { #endif -typedef unsigned long jptr; // NOLINT +typedef unsigned long jptr; // Must be called before any other callback from Java. void __tsan_java_init(jptr heap_begin, jptr heap_size) INTERFACE_ATTRIBUTE; diff --git a/libsanitizer/tsan/tsan_libdispatch.cpp b/libsanitizer/tsan/tsan_libdispatch.cpp deleted file mode 100644 index 5e86ddc4e12..00000000000 --- a/libsanitizer/tsan/tsan_libdispatch.cpp +++ /dev/null @@ -1,781 +0,0 @@ -//===-- tsan_libdispatch.cpp ----------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file is a part of ThreadSanitizer (TSan), a race detector. -// -// Support for intercepting libdispatch (GCD). -//===----------------------------------------------------------------------===// - -#include "sanitizer_common/sanitizer_common.h" -#include "interception/interception.h" -#include "tsan_interceptors.h" -#include "tsan_rtl.h" - -#include "tsan_dispatch_defs.h" - -namespace __tsan { - typedef u16 uint16_t; - -typedef struct { - dispatch_queue_t queue; - void *orig_context; - dispatch_function_t orig_work; - bool free_context_in_callback; - bool submitted_synchronously; - bool is_barrier_block; - uptr non_queue_sync_object; -} block_context_t; - -// The offsets of different fields of the dispatch_queue_t structure, exported -// by libdispatch.dylib. -extern "C" struct dispatch_queue_offsets_s { - const uint16_t dqo_version; - const uint16_t dqo_label; - const uint16_t dqo_label_size; - const uint16_t dqo_flags; - const uint16_t dqo_flags_size; - const uint16_t dqo_serialnum; - const uint16_t dqo_serialnum_size; - const uint16_t dqo_width; - const uint16_t dqo_width_size; - const uint16_t dqo_running; - const uint16_t dqo_running_size; - const uint16_t dqo_suspend_cnt; - const uint16_t dqo_suspend_cnt_size; - const uint16_t dqo_target_queue; - const uint16_t dqo_target_queue_size; - const uint16_t dqo_priority; - const uint16_t dqo_priority_size; -} dispatch_queue_offsets; - -static bool IsQueueSerial(dispatch_queue_t q) { - CHECK_EQ(dispatch_queue_offsets.dqo_width_size, 2); - uptr width = *(uint16_t *)(((uptr)q) + dispatch_queue_offsets.dqo_width); - CHECK_NE(width, 0); - return width == 1; -} - -static dispatch_queue_t GetTargetQueueFromQueue(dispatch_queue_t q) { - CHECK_EQ(dispatch_queue_offsets.dqo_target_queue_size, 8); - dispatch_queue_t tq = *( - dispatch_queue_t *)(((uptr)q) + dispatch_queue_offsets.dqo_target_queue); - return tq; -} - -static dispatch_queue_t GetTargetQueueFromSource(dispatch_source_t source) { - dispatch_queue_t tq = GetTargetQueueFromQueue((dispatch_queue_t)source); - CHECK_NE(tq, 0); - return tq; -} - -static block_context_t *AllocContext(ThreadState *thr, uptr pc, - dispatch_queue_t queue, void *orig_context, - dispatch_function_t orig_work) { - block_context_t *new_context = - (block_context_t *)user_alloc_internal(thr, pc, sizeof(block_context_t)); - new_context->queue = queue; - new_context->orig_context = orig_context; - new_context->orig_work = orig_work; - new_context->free_context_in_callback = true; - new_context->submitted_synchronously = false; - new_context->is_barrier_block = false; - new_context->non_queue_sync_object = 0; - return new_context; -} - -#define GET_QUEUE_SYNC_VARS(context, q) \ - bool is_queue_serial = q && IsQueueSerial(q); \ - uptr sync_ptr = (uptr)q ?: context->non_queue_sync_object; \ - uptr serial_sync = (uptr)sync_ptr; \ - uptr concurrent_sync = sync_ptr ? ((uptr)sync_ptr) + sizeof(uptr) : 0; \ - bool serial_task = context->is_barrier_block || is_queue_serial - -static void dispatch_sync_pre_execute(ThreadState *thr, uptr pc, - block_context_t *context) { - uptr submit_sync = (uptr)context; - Acquire(thr, pc, submit_sync); - - dispatch_queue_t q = context->queue; - do { - GET_QUEUE_SYNC_VARS(context, q); - if (serial_sync) Acquire(thr, pc, serial_sync); - if (serial_task && concurrent_sync) Acquire(thr, pc, concurrent_sync); - - if (q) q = GetTargetQueueFromQueue(q); - } while (q); -} - -static void dispatch_sync_post_execute(ThreadState *thr, uptr pc, - block_context_t *context) { - uptr submit_sync = (uptr)context; - if (context->submitted_synchronously) Release(thr, pc, submit_sync); - - dispatch_queue_t q = context->queue; - do { - GET_QUEUE_SYNC_VARS(context, q); - if (serial_task && serial_sync) Release(thr, pc, serial_sync); - if (!serial_task && concurrent_sync) Release(thr, pc, concurrent_sync); - - if (q) q = GetTargetQueueFromQueue(q); - } while (q); -} - -static void dispatch_callback_wrap(void *param) { - SCOPED_INTERCEPTOR_RAW(dispatch_callback_wrap); - block_context_t *context = (block_context_t *)param; - - dispatch_sync_pre_execute(thr, pc, context); - - SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START(); - context->orig_work(context->orig_context); - SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END(); - - dispatch_sync_post_execute(thr, pc, context); - - if (context->free_context_in_callback) user_free(thr, pc, context); -} - -static void invoke_block(void *param) { - dispatch_block_t block = (dispatch_block_t)param; - block(); -} - -static void invoke_and_release_block(void *param) { - dispatch_block_t block = (dispatch_block_t)param; - block(); - Block_release(block); -} - -#define DISPATCH_INTERCEPT_ASYNC_B(name, barrier) \ - TSAN_INTERCEPTOR(void, name, dispatch_queue_t q, dispatch_block_t block) { \ - SCOPED_TSAN_INTERCEPTOR(name, q, block); \ - SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START(); \ - dispatch_block_t heap_block = Block_copy(block); \ - SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END(); \ - block_context_t *new_context = \ - AllocContext(thr, pc, q, heap_block, &invoke_and_release_block); \ - new_context->is_barrier_block = barrier; \ - Release(thr, pc, (uptr)new_context); \ - SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START(); \ - REAL(name##_f)(q, new_context, dispatch_callback_wrap); \ - SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END(); \ - } - -#define DISPATCH_INTERCEPT_SYNC_B(name, barrier) \ - TSAN_INTERCEPTOR(void, name, dispatch_queue_t q, \ - DISPATCH_NOESCAPE dispatch_block_t block) { \ - SCOPED_TSAN_INTERCEPTOR(name, q, block); \ - block_context_t new_context = { \ - q, block, &invoke_block, false, true, barrier, 0}; \ - Release(thr, pc, (uptr)&new_context); \ - SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START(); \ - REAL(name##_f)(q, &new_context, dispatch_callback_wrap); \ - SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END(); \ - Acquire(thr, pc, (uptr)&new_context); \ - } - -#define DISPATCH_INTERCEPT_ASYNC_F(name, barrier) \ - TSAN_INTERCEPTOR(void, name, dispatch_queue_t q, void *context, \ - dispatch_function_t work) { \ - SCOPED_TSAN_INTERCEPTOR(name, q, context, work); \ - block_context_t *new_context = \ - AllocContext(thr, pc, q, context, work); \ - new_context->is_barrier_block = barrier; \ - Release(thr, pc, (uptr)new_context); \ - SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START(); \ - REAL(name)(q, new_context, dispatch_callback_wrap); \ - SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END(); \ - } - -#define DISPATCH_INTERCEPT_SYNC_F(name, barrier) \ - TSAN_INTERCEPTOR(void, name, dispatch_queue_t q, void *context, \ - dispatch_function_t work) { \ - SCOPED_TSAN_INTERCEPTOR(name, q, context, work); \ - block_context_t new_context = { \ - q, context, work, false, true, barrier, 0}; \ - Release(thr, pc, (uptr)&new_context); \ - SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START(); \ - REAL(name)(q, &new_context, dispatch_callback_wrap); \ - SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END(); \ - Acquire(thr, pc, (uptr)&new_context); \ - } - -#define DISPATCH_INTERCEPT(name, barrier) \ - DISPATCH_INTERCEPT_ASYNC_F(name##_async_f, barrier) \ - DISPATCH_INTERCEPT_ASYNC_B(name##_async, barrier) \ - DISPATCH_INTERCEPT_SYNC_F(name##_sync_f, barrier) \ - DISPATCH_INTERCEPT_SYNC_B(name##_sync, barrier) - -// We wrap dispatch_async, dispatch_sync and friends where we allocate a new -// context, which is used to synchronize (we release the context before -// submitting, and the callback acquires it before executing the original -// callback). -DISPATCH_INTERCEPT(dispatch, false) -DISPATCH_INTERCEPT(dispatch_barrier, true) - -DECLARE_REAL(void, dispatch_after_f, dispatch_time_t when, - dispatch_queue_t queue, void *context, dispatch_function_t work) - -TSAN_INTERCEPTOR(void, dispatch_after, dispatch_time_t when, - dispatch_queue_t queue, dispatch_block_t block) { - SCOPED_TSAN_INTERCEPTOR(dispatch_after, when, queue, block); - SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START(); - dispatch_block_t heap_block = Block_copy(block); - SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END(); - block_context_t *new_context = - AllocContext(thr, pc, queue, heap_block, &invoke_and_release_block); - Release(thr, pc, (uptr)new_context); - SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START(); - REAL(dispatch_after_f)(when, queue, new_context, dispatch_callback_wrap); - SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END(); -} - -TSAN_INTERCEPTOR(void, dispatch_after_f, dispatch_time_t when, - dispatch_queue_t queue, void *context, - dispatch_function_t work) { - SCOPED_TSAN_INTERCEPTOR(dispatch_after_f, when, queue, context, work); - WRAP(dispatch_after)(when, queue, ^(void) { - work(context); - }); -} - -// GCD's dispatch_once implementation has a fast path that contains a racy read -// and it's inlined into user's code. Furthermore, this fast path doesn't -// establish a proper happens-before relations between the initialization and -// code following the call to dispatch_once. We could deal with this in -// instrumented code, but there's not much we can do about it in system -// libraries. Let's disable the fast path (by never storing the value ~0 to -// predicate), so the interceptor is always called, and let's add proper release -// and acquire semantics. Since TSan does not see its own atomic stores, the -// race on predicate won't be reported - the only accesses to it that TSan sees -// are the loads on the fast path. Loads don't race. Secondly, dispatch_once is -// both a macro and a real function, we want to intercept the function, so we -// need to undefine the macro. -#undef dispatch_once -TSAN_INTERCEPTOR(void, dispatch_once, dispatch_once_t *predicate, - DISPATCH_NOESCAPE dispatch_block_t block) { - SCOPED_INTERCEPTOR_RAW(dispatch_once, predicate, block); - atomic_uint32_t *a = reinterpret_cast(predicate); - u32 v = atomic_load(a, memory_order_acquire); - if (v == 0 && - atomic_compare_exchange_strong(a, &v, 1, memory_order_relaxed)) { - SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START(); - block(); - SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END(); - Release(thr, pc, (uptr)a); - atomic_store(a, 2, memory_order_release); - } else { - while (v != 2) { - internal_sched_yield(); - v = atomic_load(a, memory_order_acquire); - } - Acquire(thr, pc, (uptr)a); - } -} - -#undef dispatch_once_f -TSAN_INTERCEPTOR(void, dispatch_once_f, dispatch_once_t *predicate, - void *context, dispatch_function_t function) { - SCOPED_INTERCEPTOR_RAW(dispatch_once_f, predicate, context, function); - SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START(); - WRAP(dispatch_once)(predicate, ^(void) { - function(context); - }); - SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END(); -} - -TSAN_INTERCEPTOR(long_t, dispatch_semaphore_signal, - dispatch_semaphore_t dsema) { - SCOPED_TSAN_INTERCEPTOR(dispatch_semaphore_signal, dsema); - Release(thr, pc, (uptr)dsema); - return REAL(dispatch_semaphore_signal)(dsema); -} - -TSAN_INTERCEPTOR(long_t, dispatch_semaphore_wait, dispatch_semaphore_t dsema, - dispatch_time_t timeout) { - SCOPED_TSAN_INTERCEPTOR(dispatch_semaphore_wait, dsema, timeout); - long_t result = REAL(dispatch_semaphore_wait)(dsema, timeout); - if (result == 0) Acquire(thr, pc, (uptr)dsema); - return result; -} - -TSAN_INTERCEPTOR(long_t, dispatch_group_wait, dispatch_group_t group, - dispatch_time_t timeout) { - SCOPED_TSAN_INTERCEPTOR(dispatch_group_wait, group, timeout); - long_t result = REAL(dispatch_group_wait)(group, timeout); - if (result == 0) Acquire(thr, pc, (uptr)group); - return result; -} - -// Used, but not intercepted. -extern "C" void dispatch_group_enter(dispatch_group_t group); - -TSAN_INTERCEPTOR(void, dispatch_group_leave, dispatch_group_t group) { - SCOPED_TSAN_INTERCEPTOR(dispatch_group_leave, group); - // Acquired in the group notification callback in dispatch_group_notify[_f]. - Release(thr, pc, (uptr)group); - REAL(dispatch_group_leave)(group); -} - -TSAN_INTERCEPTOR(void, dispatch_group_async, dispatch_group_t group, - dispatch_queue_t queue, dispatch_block_t block) { - SCOPED_TSAN_INTERCEPTOR(dispatch_group_async, group, queue, block); - dispatch_retain(group); - dispatch_group_enter(group); - __block dispatch_block_t block_copy = (dispatch_block_t)Block_copy(block); - WRAP(dispatch_async)(queue, ^(void) { - block_copy(); - Block_release(block_copy); - WRAP(dispatch_group_leave)(group); - dispatch_release(group); - }); -} - -TSAN_INTERCEPTOR(void, dispatch_group_async_f, dispatch_group_t group, - dispatch_queue_t queue, void *context, - dispatch_function_t work) { - SCOPED_TSAN_INTERCEPTOR(dispatch_group_async_f, group, queue, context, work); - dispatch_retain(group); - dispatch_group_enter(group); - WRAP(dispatch_async)(queue, ^(void) { - work(context); - WRAP(dispatch_group_leave)(group); - dispatch_release(group); - }); -} - -DECLARE_REAL(void, dispatch_group_notify_f, dispatch_group_t group, - dispatch_queue_t q, void *context, dispatch_function_t work) - -TSAN_INTERCEPTOR(void, dispatch_group_notify, dispatch_group_t group, - dispatch_queue_t q, dispatch_block_t block) { - SCOPED_TSAN_INTERCEPTOR(dispatch_group_notify, group, q, block); - - // To make sure the group is still available in the callback (otherwise - // it can be already destroyed). Will be released in the callback. - dispatch_retain(group); - - SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START(); - dispatch_block_t heap_block = Block_copy(^(void) { - { - SCOPED_INTERCEPTOR_RAW(dispatch_read_callback); - // Released when leaving the group (dispatch_group_leave). - Acquire(thr, pc, (uptr)group); - } - dispatch_release(group); - block(); - }); - SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END(); - block_context_t *new_context = - AllocContext(thr, pc, q, heap_block, &invoke_and_release_block); - new_context->is_barrier_block = true; - Release(thr, pc, (uptr)new_context); - REAL(dispatch_group_notify_f)(group, q, new_context, dispatch_callback_wrap); -} - -TSAN_INTERCEPTOR(void, dispatch_group_notify_f, dispatch_group_t group, - dispatch_queue_t q, void *context, dispatch_function_t work) { - WRAP(dispatch_group_notify)(group, q, ^(void) { work(context); }); -} - -TSAN_INTERCEPTOR(void, dispatch_source_set_event_handler, - dispatch_source_t source, dispatch_block_t handler) { - SCOPED_TSAN_INTERCEPTOR(dispatch_source_set_event_handler, source, handler); - if (handler == nullptr) - return REAL(dispatch_source_set_event_handler)(source, nullptr); - dispatch_queue_t q = GetTargetQueueFromSource(source); - __block block_context_t new_context = { - q, handler, &invoke_block, false, false, false, 0 }; - dispatch_block_t new_handler = Block_copy(^(void) { - new_context.orig_context = handler; // To explicitly capture "handler". - dispatch_callback_wrap(&new_context); - }); - uptr submit_sync = (uptr)&new_context; - Release(thr, pc, submit_sync); - REAL(dispatch_source_set_event_handler)(source, new_handler); - Block_release(new_handler); -} - -TSAN_INTERCEPTOR(void, dispatch_source_set_event_handler_f, - dispatch_source_t source, dispatch_function_t handler) { - SCOPED_TSAN_INTERCEPTOR(dispatch_source_set_event_handler_f, source, handler); - if (handler == nullptr) - return REAL(dispatch_source_set_event_handler)(source, nullptr); - dispatch_block_t block = ^(void) { - handler(dispatch_get_context(source)); - }; - WRAP(dispatch_source_set_event_handler)(source, block); -} - -TSAN_INTERCEPTOR(void, dispatch_source_set_cancel_handler, - dispatch_source_t source, dispatch_block_t handler) { - SCOPED_TSAN_INTERCEPTOR(dispatch_source_set_cancel_handler, source, handler); - if (handler == nullptr) - return REAL(dispatch_source_set_cancel_handler)(source, nullptr); - dispatch_queue_t q = GetTargetQueueFromSource(source); - __block block_context_t new_context = { - q, handler, &invoke_block, false, false, false, 0}; - dispatch_block_t new_handler = Block_copy(^(void) { - new_context.orig_context = handler; // To explicitly capture "handler". - dispatch_callback_wrap(&new_context); - }); - uptr submit_sync = (uptr)&new_context; - Release(thr, pc, submit_sync); - REAL(dispatch_source_set_cancel_handler)(source, new_handler); - Block_release(new_handler); -} - -TSAN_INTERCEPTOR(void, dispatch_source_set_cancel_handler_f, - dispatch_source_t source, dispatch_function_t handler) { - SCOPED_TSAN_INTERCEPTOR(dispatch_source_set_cancel_handler_f, source, - handler); - if (handler == nullptr) - return REAL(dispatch_source_set_cancel_handler)(source, nullptr); - dispatch_block_t block = ^(void) { - handler(dispatch_get_context(source)); - }; - WRAP(dispatch_source_set_cancel_handler)(source, block); -} - -TSAN_INTERCEPTOR(void, dispatch_source_set_registration_handler, - dispatch_source_t source, dispatch_block_t handler) { - SCOPED_TSAN_INTERCEPTOR(dispatch_source_set_registration_handler, source, - handler); - if (handler == nullptr) - return REAL(dispatch_source_set_registration_handler)(source, nullptr); - dispatch_queue_t q = GetTargetQueueFromSource(source); - __block block_context_t new_context = { - q, handler, &invoke_block, false, false, false, 0}; - dispatch_block_t new_handler = Block_copy(^(void) { - new_context.orig_context = handler; // To explicitly capture "handler". - dispatch_callback_wrap(&new_context); - }); - uptr submit_sync = (uptr)&new_context; - Release(thr, pc, submit_sync); - REAL(dispatch_source_set_registration_handler)(source, new_handler); - Block_release(new_handler); -} - -TSAN_INTERCEPTOR(void, dispatch_source_set_registration_handler_f, - dispatch_source_t source, dispatch_function_t handler) { - SCOPED_TSAN_INTERCEPTOR(dispatch_source_set_registration_handler_f, source, - handler); - if (handler == nullptr) - return REAL(dispatch_source_set_registration_handler)(source, nullptr); - dispatch_block_t block = ^(void) { - handler(dispatch_get_context(source)); - }; - WRAP(dispatch_source_set_registration_handler)(source, block); -} - -TSAN_INTERCEPTOR(void, dispatch_apply, size_t iterations, - dispatch_queue_t queue, - DISPATCH_NOESCAPE void (^block)(size_t)) { - SCOPED_TSAN_INTERCEPTOR(dispatch_apply, iterations, queue, block); - - u8 sync1, sync2; - uptr parent_to_child_sync = (uptr)&sync1; - uptr child_to_parent_sync = (uptr)&sync2; - - Release(thr, pc, parent_to_child_sync); - void (^new_block)(size_t) = ^(size_t iteration) { - SCOPED_INTERCEPTOR_RAW(dispatch_apply); - Acquire(thr, pc, parent_to_child_sync); - SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START(); - block(iteration); - SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END(); - Release(thr, pc, child_to_parent_sync); - }; - SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START(); - REAL(dispatch_apply)(iterations, queue, new_block); - SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END(); - Acquire(thr, pc, child_to_parent_sync); -} - -static void invoke_block_iteration(void *param, size_t iteration) { - auto block = (void (^)(size_t)) param; - block(iteration); -} - -TSAN_INTERCEPTOR(void, dispatch_apply_f, size_t iterations, - dispatch_queue_t queue, void *context, - void (*work)(void *, size_t)) { - SCOPED_TSAN_INTERCEPTOR(dispatch_apply_f, iterations, queue, context, work); - - // Unfortunately, we cannot delegate to dispatch_apply, since libdispatch - // implements dispatch_apply in terms of dispatch_apply_f. - u8 sync1, sync2; - uptr parent_to_child_sync = (uptr)&sync1; - uptr child_to_parent_sync = (uptr)&sync2; - - Release(thr, pc, parent_to_child_sync); - void (^new_block)(size_t) = ^(size_t iteration) { - SCOPED_INTERCEPTOR_RAW(dispatch_apply_f); - Acquire(thr, pc, parent_to_child_sync); - SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START(); - work(context, iteration); - SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END(); - Release(thr, pc, child_to_parent_sync); - }; - SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START(); - REAL(dispatch_apply_f)(iterations, queue, new_block, invoke_block_iteration); - SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END(); - Acquire(thr, pc, child_to_parent_sync); -} - -DECLARE_REAL_AND_INTERCEPTOR(void, free, void *ptr) -DECLARE_REAL_AND_INTERCEPTOR(int, munmap, void *addr, long_t sz) - -TSAN_INTERCEPTOR(dispatch_data_t, dispatch_data_create, const void *buffer, - size_t size, dispatch_queue_t q, dispatch_block_t destructor) { - SCOPED_TSAN_INTERCEPTOR(dispatch_data_create, buffer, size, q, destructor); - if ((q == nullptr) || (destructor == DISPATCH_DATA_DESTRUCTOR_DEFAULT)) - return REAL(dispatch_data_create)(buffer, size, q, destructor); - - if (destructor == DISPATCH_DATA_DESTRUCTOR_FREE) - destructor = ^(void) { WRAP(free)((void *)(uintptr_t)buffer); }; - else if (destructor == DISPATCH_DATA_DESTRUCTOR_MUNMAP) - destructor = ^(void) { WRAP(munmap)((void *)(uintptr_t)buffer, size); }; - - SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START(); - dispatch_block_t heap_block = Block_copy(destructor); - SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END(); - block_context_t *new_context = - AllocContext(thr, pc, q, heap_block, &invoke_and_release_block); - uptr submit_sync = (uptr)new_context; - Release(thr, pc, submit_sync); - return REAL(dispatch_data_create)(buffer, size, q, ^(void) { - dispatch_callback_wrap(new_context); - }); -} - -typedef void (^fd_handler_t)(dispatch_data_t data, int error); -typedef void (^cleanup_handler_t)(int error); - -TSAN_INTERCEPTOR(void, dispatch_read, dispatch_fd_t fd, size_t length, - dispatch_queue_t q, fd_handler_t h) { - SCOPED_TSAN_INTERCEPTOR(dispatch_read, fd, length, q, h); - __block block_context_t new_context = { - q, nullptr, &invoke_block, false, false, false, 0}; - fd_handler_t new_h = Block_copy(^(dispatch_data_t data, int error) { - new_context.orig_context = ^(void) { - h(data, error); - }; - dispatch_callback_wrap(&new_context); - }); - uptr submit_sync = (uptr)&new_context; - Release(thr, pc, submit_sync); - REAL(dispatch_read)(fd, length, q, new_h); - Block_release(new_h); -} - -TSAN_INTERCEPTOR(void, dispatch_write, dispatch_fd_t fd, dispatch_data_t data, - dispatch_queue_t q, fd_handler_t h) { - SCOPED_TSAN_INTERCEPTOR(dispatch_write, fd, data, q, h); - __block block_context_t new_context = { - q, nullptr, &invoke_block, false, false, false, 0}; - fd_handler_t new_h = Block_copy(^(dispatch_data_t data, int error) { - new_context.orig_context = ^(void) { - h(data, error); - }; - dispatch_callback_wrap(&new_context); - }); - uptr submit_sync = (uptr)&new_context; - Release(thr, pc, submit_sync); - REAL(dispatch_write)(fd, data, q, new_h); - Block_release(new_h); -} - -TSAN_INTERCEPTOR(void, dispatch_io_read, dispatch_io_t channel, off_t offset, - size_t length, dispatch_queue_t q, dispatch_io_handler_t h) { - SCOPED_TSAN_INTERCEPTOR(dispatch_io_read, channel, offset, length, q, h); - __block block_context_t new_context = { - q, nullptr, &invoke_block, false, false, false, 0}; - dispatch_io_handler_t new_h = - Block_copy(^(bool done, dispatch_data_t data, int error) { - new_context.orig_context = ^(void) { - h(done, data, error); - }; - dispatch_callback_wrap(&new_context); - }); - uptr submit_sync = (uptr)&new_context; - Release(thr, pc, submit_sync); - REAL(dispatch_io_read)(channel, offset, length, q, new_h); - Block_release(new_h); -} - -TSAN_INTERCEPTOR(void, dispatch_io_write, dispatch_io_t channel, off_t offset, - dispatch_data_t data, dispatch_queue_t q, - dispatch_io_handler_t h) { - SCOPED_TSAN_INTERCEPTOR(dispatch_io_write, channel, offset, data, q, h); - __block block_context_t new_context = { - q, nullptr, &invoke_block, false, false, false, 0}; - dispatch_io_handler_t new_h = - Block_copy(^(bool done, dispatch_data_t data, int error) { - new_context.orig_context = ^(void) { - h(done, data, error); - }; - dispatch_callback_wrap(&new_context); - }); - uptr submit_sync = (uptr)&new_context; - Release(thr, pc, submit_sync); - REAL(dispatch_io_write)(channel, offset, data, q, new_h); - Block_release(new_h); -} - -TSAN_INTERCEPTOR(void, dispatch_io_barrier, dispatch_io_t channel, - dispatch_block_t barrier) { - SCOPED_TSAN_INTERCEPTOR(dispatch_io_barrier, channel, barrier); - __block block_context_t new_context = { - nullptr, nullptr, &invoke_block, false, false, false, 0}; - new_context.non_queue_sync_object = (uptr)channel; - new_context.is_barrier_block = true; - dispatch_block_t new_block = Block_copy(^(void) { - new_context.orig_context = ^(void) { - barrier(); - }; - dispatch_callback_wrap(&new_context); - }); - uptr submit_sync = (uptr)&new_context; - Release(thr, pc, submit_sync); - REAL(dispatch_io_barrier)(channel, new_block); - Block_release(new_block); -} - -TSAN_INTERCEPTOR(dispatch_io_t, dispatch_io_create, dispatch_io_type_t type, - dispatch_fd_t fd, dispatch_queue_t q, cleanup_handler_t h) { - SCOPED_TSAN_INTERCEPTOR(dispatch_io_create, type, fd, q, h); - __block dispatch_io_t new_channel = nullptr; - __block block_context_t new_context = { - q, nullptr, &invoke_block, false, false, false, 0}; - cleanup_handler_t new_h = Block_copy(^(int error) { - { - SCOPED_INTERCEPTOR_RAW(dispatch_io_create_callback); - Acquire(thr, pc, (uptr)new_channel); // Release() in dispatch_io_close. - } - new_context.orig_context = ^(void) { - h(error); - }; - dispatch_callback_wrap(&new_context); - }); - uptr submit_sync = (uptr)&new_context; - Release(thr, pc, submit_sync); - new_channel = REAL(dispatch_io_create)(type, fd, q, new_h); - Block_release(new_h); - return new_channel; -} - -TSAN_INTERCEPTOR(dispatch_io_t, dispatch_io_create_with_path, - dispatch_io_type_t type, const char *path, int oflag, - mode_t mode, dispatch_queue_t q, cleanup_handler_t h) { - SCOPED_TSAN_INTERCEPTOR(dispatch_io_create_with_path, type, path, oflag, mode, - q, h); - __block dispatch_io_t new_channel = nullptr; - __block block_context_t new_context = { - q, nullptr, &invoke_block, false, false, false, 0}; - cleanup_handler_t new_h = Block_copy(^(int error) { - { - SCOPED_INTERCEPTOR_RAW(dispatch_io_create_callback); - Acquire(thr, pc, (uptr)new_channel); // Release() in dispatch_io_close. - } - new_context.orig_context = ^(void) { - h(error); - }; - dispatch_callback_wrap(&new_context); - }); - uptr submit_sync = (uptr)&new_context; - Release(thr, pc, submit_sync); - new_channel = - REAL(dispatch_io_create_with_path)(type, path, oflag, mode, q, new_h); - Block_release(new_h); - return new_channel; -} - -TSAN_INTERCEPTOR(dispatch_io_t, dispatch_io_create_with_io, - dispatch_io_type_t type, dispatch_io_t io, dispatch_queue_t q, - cleanup_handler_t h) { - SCOPED_TSAN_INTERCEPTOR(dispatch_io_create_with_io, type, io, q, h); - __block dispatch_io_t new_channel = nullptr; - __block block_context_t new_context = { - q, nullptr, &invoke_block, false, false, false, 0}; - cleanup_handler_t new_h = Block_copy(^(int error) { - { - SCOPED_INTERCEPTOR_RAW(dispatch_io_create_callback); - Acquire(thr, pc, (uptr)new_channel); // Release() in dispatch_io_close. - } - new_context.orig_context = ^(void) { - h(error); - }; - dispatch_callback_wrap(&new_context); - }); - uptr submit_sync = (uptr)&new_context; - Release(thr, pc, submit_sync); - new_channel = REAL(dispatch_io_create_with_io)(type, io, q, new_h); - Block_release(new_h); - return new_channel; -} - -TSAN_INTERCEPTOR(void, dispatch_io_close, dispatch_io_t channel, - dispatch_io_close_flags_t flags) { - SCOPED_TSAN_INTERCEPTOR(dispatch_io_close, channel, flags); - Release(thr, pc, (uptr)channel); // Acquire() in dispatch_io_create[_*]. - return REAL(dispatch_io_close)(channel, flags); -} - -// Resuming a suspended queue needs to synchronize with all subsequent -// executions of blocks in that queue. -TSAN_INTERCEPTOR(void, dispatch_resume, dispatch_object_t o) { - SCOPED_TSAN_INTERCEPTOR(dispatch_resume, o); - Release(thr, pc, (uptr)o); // Synchronizes with the Acquire() on serial_sync - // in dispatch_sync_pre_execute - return REAL(dispatch_resume)(o); -} - -void InitializeLibdispatchInterceptors() { - INTERCEPT_FUNCTION(dispatch_async); - INTERCEPT_FUNCTION(dispatch_async_f); - INTERCEPT_FUNCTION(dispatch_sync); - INTERCEPT_FUNCTION(dispatch_sync_f); - INTERCEPT_FUNCTION(dispatch_barrier_async); - INTERCEPT_FUNCTION(dispatch_barrier_async_f); - INTERCEPT_FUNCTION(dispatch_barrier_sync); - INTERCEPT_FUNCTION(dispatch_barrier_sync_f); - INTERCEPT_FUNCTION(dispatch_after); - INTERCEPT_FUNCTION(dispatch_after_f); - INTERCEPT_FUNCTION(dispatch_once); - INTERCEPT_FUNCTION(dispatch_once_f); - INTERCEPT_FUNCTION(dispatch_semaphore_signal); - INTERCEPT_FUNCTION(dispatch_semaphore_wait); - INTERCEPT_FUNCTION(dispatch_group_wait); - INTERCEPT_FUNCTION(dispatch_group_leave); - INTERCEPT_FUNCTION(dispatch_group_async); - INTERCEPT_FUNCTION(dispatch_group_async_f); - INTERCEPT_FUNCTION(dispatch_group_notify); - INTERCEPT_FUNCTION(dispatch_group_notify_f); - INTERCEPT_FUNCTION(dispatch_source_set_event_handler); - INTERCEPT_FUNCTION(dispatch_source_set_event_handler_f); - INTERCEPT_FUNCTION(dispatch_source_set_cancel_handler); - INTERCEPT_FUNCTION(dispatch_source_set_cancel_handler_f); - INTERCEPT_FUNCTION(dispatch_source_set_registration_handler); - INTERCEPT_FUNCTION(dispatch_source_set_registration_handler_f); - INTERCEPT_FUNCTION(dispatch_apply); - INTERCEPT_FUNCTION(dispatch_apply_f); - INTERCEPT_FUNCTION(dispatch_data_create); - INTERCEPT_FUNCTION(dispatch_read); - INTERCEPT_FUNCTION(dispatch_write); - INTERCEPT_FUNCTION(dispatch_io_read); - INTERCEPT_FUNCTION(dispatch_io_write); - INTERCEPT_FUNCTION(dispatch_io_barrier); - INTERCEPT_FUNCTION(dispatch_io_create); - INTERCEPT_FUNCTION(dispatch_io_create_with_path); - INTERCEPT_FUNCTION(dispatch_io_create_with_io); - INTERCEPT_FUNCTION(dispatch_io_close); - INTERCEPT_FUNCTION(dispatch_resume); -} - -} // namespace __tsan diff --git a/libsanitizer/tsan/tsan_md5.cpp b/libsanitizer/tsan/tsan_md5.cpp index d146e1cc35f..72857b773fe 100644 --- a/libsanitizer/tsan/tsan_md5.cpp +++ b/libsanitizer/tsan/tsan_md5.cpp @@ -29,7 +29,7 @@ namespace __tsan { SET(n) typedef unsigned int MD5_u32plus; -typedef unsigned long ulong_t; // NOLINT +typedef unsigned long ulong_t; typedef struct { MD5_u32plus lo, hi; diff --git a/libsanitizer/tsan/tsan_mman.h b/libsanitizer/tsan/tsan_mman.h index 467aabdf2b9..a5280d4472c 100644 --- a/libsanitizer/tsan/tsan_mman.h +++ b/libsanitizer/tsan/tsan_mman.h @@ -79,11 +79,10 @@ enum MBlockType { void *internal_alloc(MBlockType typ, uptr sz); void internal_free(void *p); -template -void DestroyAndFree(T *&p) { +template +void DestroyAndFree(T *p) { p->~T(); internal_free(p); - p = 0; } } // namespace __tsan diff --git a/libsanitizer/tsan/tsan_new_delete.cpp b/libsanitizer/tsan/tsan_new_delete.cpp index 3ed3c847a9a..fc44a5221b5 100644 --- a/libsanitizer/tsan/tsan_new_delete.cpp +++ b/libsanitizer/tsan/tsan_new_delete.cpp @@ -17,7 +17,7 @@ #include "tsan_interceptors.h" #include "tsan_rtl.h" -using namespace __tsan; // NOLINT +using namespace __tsan; namespace std { struct nothrow_t {}; diff --git a/libsanitizer/tsan/tsan_platform.h b/libsanitizer/tsan/tsan_platform.h index 0d106c4147c..63eb14fcd34 100644 --- a/libsanitizer/tsan/tsan_platform.h +++ b/libsanitizer/tsan/tsan_platform.h @@ -457,6 +457,8 @@ struct Mapping47 { static const uptr kAppMemEnd = 0x00e000000000ull; }; +#define TSAN_RUNTIME_VMA 1 + #elif SANITIZER_GO && defined(__aarch64__) /* Go on linux/aarch64 (48-bit VMA) diff --git a/libsanitizer/tsan/tsan_report.cpp b/libsanitizer/tsan/tsan_report.cpp index 655aa5f9123..368f1ca8adf 100644 --- a/libsanitizer/tsan/tsan_report.cpp +++ b/libsanitizer/tsan/tsan_report.cpp @@ -298,7 +298,7 @@ static bool FrameIsInternal(const SymbolizedStack *frame) { const char *file = frame->info.file; const char *module = frame->info.module; if (file != 0 && - (internal_strstr(file, "tsan_interceptors.cpp") || + (internal_strstr(file, "tsan_interceptors_posix.cpp") || internal_strstr(file, "sanitizer_common_interceptors.inc") || internal_strstr(file, "tsan_interface_"))) return true; diff --git a/libsanitizer/tsan/tsan_rtl.cpp b/libsanitizer/tsan/tsan_rtl.cpp index 1ac3907094b..3f3c0cce119 100644 --- a/libsanitizer/tsan/tsan_rtl.cpp +++ b/libsanitizer/tsan/tsan_rtl.cpp @@ -239,6 +239,15 @@ void DontNeedShadowFor(uptr addr, uptr size) { ReleaseMemoryPagesToOS(MemToShadow(addr), MemToShadow(addr + size)); } +#if !SANITIZER_GO +void UnmapShadow(ThreadState *thr, uptr addr, uptr size) { + if (size == 0) return; + DontNeedShadowFor(addr, size); + ScopedGlobalProcessor sgp; + ctx->metamap.ResetRange(thr->proc(), addr, size); +} +#endif + void MapShadow(uptr addr, uptr size) { // Global data is not 64K aligned, but there are no adjacent mappings, // so we can get away with unaligned mapping. @@ -329,7 +338,7 @@ static void CheckShadowMapping() { #if !SANITIZER_GO static void OnStackUnwind(const SignalContext &sig, const void *, BufferedStackTrace *stack) { - stack->Unwind(sig.pc, sig.bp, sig.context, + stack->Unwind(StackTrace::GetNextInstructionPc(sig.pc), sig.bp, sig.context, common_flags()->fast_unwind_on_fatal); } @@ -987,6 +996,14 @@ void MemoryRangeImitateWrite(ThreadState *thr, uptr pc, uptr addr, uptr size) { MemoryRangeSet(thr, pc, addr, size, s.raw()); } +void MemoryRangeImitateWriteOrResetRange(ThreadState *thr, uptr pc, uptr addr, + uptr size) { + if (thr->ignore_reads_and_writes == 0) + MemoryRangeImitateWrite(thr, pc, addr, size); + else + MemoryResetRange(thr, pc, addr, size); +} + ALWAYS_INLINE USED void FuncEntry(ThreadState *thr, uptr pc) { StatInc(thr, StatFuncEnter); diff --git a/libsanitizer/tsan/tsan_rtl.h b/libsanitizer/tsan/tsan_rtl.h index 3a8231bda9a..c38fc43a9f8 100644 --- a/libsanitizer/tsan/tsan_rtl.h +++ b/libsanitizer/tsan/tsan_rtl.h @@ -238,7 +238,7 @@ class Shadow : public FastState { unsigned kS2AccessSize) { bool res = false; u64 diff = s1.addr0() - s2.addr0(); - if ((s64)diff < 0) { // s1.addr0 < s2.addr0 // NOLINT + if ((s64)diff < 0) { // s1.addr0 < s2.addr0 // if (s1.addr0() + size1) > s2.addr0()) return true; if (s1.size() > -diff) res = true; @@ -680,6 +680,7 @@ void ALWAYS_INLINE StatSet(ThreadState *thr, StatType typ, u64 n) { void MapShadow(uptr addr, uptr size); void MapThreadTrace(uptr addr, uptr size, const char *name); void DontNeedShadowFor(uptr addr, uptr size); +void UnmapShadow(ThreadState *thr, uptr addr, uptr size); void InitializeShadowMemory(); void InitializeInterceptors(); void InitializeLibIgnore(); @@ -759,6 +760,8 @@ void ALWAYS_INLINE MemoryWriteAtomic(ThreadState *thr, uptr pc, void MemoryResetRange(ThreadState *thr, uptr pc, uptr addr, uptr size); void MemoryRangeFreed(ThreadState *thr, uptr pc, uptr addr, uptr size); void MemoryRangeImitateWrite(ThreadState *thr, uptr pc, uptr addr, uptr size); +void MemoryRangeImitateWriteOrResetRange(ThreadState *thr, uptr pc, uptr addr, + uptr size); void ThreadIgnoreBegin(ThreadState *thr, uptr pc, bool save_stack = true); void ThreadIgnoreEnd(ThreadState *thr, uptr pc); diff --git a/libsanitizer/tsan/tsan_rtl_ppc64.S b/libsanitizer/tsan/tsan_rtl_ppc64.S index 9e533a71a9c..8285e21aa1e 100644 --- a/libsanitizer/tsan/tsan_rtl_ppc64.S +++ b/libsanitizer/tsan/tsan_rtl_ppc64.S @@ -1,6 +1,5 @@ #include "tsan_ppc_regs.h" - .machine altivec .section .text .hidden __tsan_setjmp .globl _setjmp diff --git a/libsanitizer/tsan/tsan_rtl_report.cpp b/libsanitizer/tsan/tsan_rtl_report.cpp index 47b8bf77dca..949beac1c55 100644 --- a/libsanitizer/tsan/tsan_rtl_report.cpp +++ b/libsanitizer/tsan/tsan_rtl_report.cpp @@ -27,7 +27,7 @@ namespace __tsan { -using namespace __sanitizer; // NOLINT +using namespace __sanitizer; static ReportStack *SymbolizeStack(StackTrace trace); @@ -154,6 +154,7 @@ ScopedReportBase::ScopedReportBase(ReportType typ, uptr tag) { ScopedReportBase::~ScopedReportBase() { ctx->report_mtx.Unlock(); DestroyAndFree(rep_); + rep_ = nullptr; } void ScopedReportBase::AddStack(StackTrace stack, bool suppressable) { @@ -700,7 +701,7 @@ void ReportRace(ThreadState *thr) { rep.AddLocation(addr_min, addr_max - addr_min); #if !SANITIZER_GO - { // NOLINT + { Shadow s(thr->racy_state[1]); if (s.epoch() <= thr->last_sleep_clock.get(s.tid())) rep.AddSleep(thr->last_sleep_stack_id); diff --git a/libsanitizer/tsan/tsan_suppressions.cpp b/libsanitizer/tsan/tsan_suppressions.cpp index 6bf6720210a..a1c1bf81bf6 100644 --- a/libsanitizer/tsan/tsan_suppressions.cpp +++ b/libsanitizer/tsan/tsan_suppressions.cpp @@ -50,7 +50,7 @@ static const char *kSuppressionTypes[] = { void InitializeSuppressions() { CHECK_EQ(nullptr, suppression_ctx); - suppression_ctx = new (suppression_placeholder) // NOLINT + suppression_ctx = new (suppression_placeholder) SuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes)); suppression_ctx->ParseFromFile(flags()->suppressions); #if !SANITIZER_GO diff --git a/libsanitizer/ubsan/ubsan_checks.inc b/libsanitizer/ubsan/ubsan_checks.inc index 7e7216c5b4a..33a8dfcde02 100644 --- a/libsanitizer/ubsan/ubsan_checks.inc +++ b/libsanitizer/ubsan/ubsan_checks.inc @@ -18,6 +18,11 @@ UBSAN_CHECK(GenericUB, "undefined-behavior", "undefined") UBSAN_CHECK(NullPointerUse, "null-pointer-use", "null") +UBSAN_CHECK(NullptrWithOffset, "nullptr-with-offset", "pointer-overflow") +UBSAN_CHECK(NullptrWithNonZeroOffset, "nullptr-with-nonzero-offset", + "pointer-overflow") +UBSAN_CHECK(NullptrAfterNonZeroOffset, "nullptr-after-nonzero-offset", + "pointer-overflow") UBSAN_CHECK(PointerOverflow, "pointer-overflow", "pointer-overflow") UBSAN_CHECK(MisalignedPointerUse, "misaligned-pointer-use", "alignment") UBSAN_CHECK(AlignmentAssumption, "alignment-assumption", "alignment") diff --git a/libsanitizer/ubsan/ubsan_diag.cpp b/libsanitizer/ubsan/ubsan_diag.cpp index c8f7960db42..1b2828d236d 100644 --- a/libsanitizer/ubsan/ubsan_diag.cpp +++ b/libsanitizer/ubsan/ubsan_diag.cpp @@ -404,7 +404,7 @@ static const char *kSuppressionTypes[] = { void __ubsan::InitializeSuppressions() { CHECK_EQ(nullptr, suppression_ctx); - suppression_ctx = new (suppression_placeholder) // NOLINT + suppression_ctx = new (suppression_placeholder) SuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes)); suppression_ctx->ParseFromFile(flags()->suppressions); } diff --git a/libsanitizer/ubsan/ubsan_flags.cpp b/libsanitizer/ubsan/ubsan_flags.cpp index 80de2a6d101..721c2273f13 100644 --- a/libsanitizer/ubsan/ubsan_flags.cpp +++ b/libsanitizer/ubsan/ubsan_flags.cpp @@ -54,7 +54,6 @@ void InitializeFlags() { { CommonFlags cf; cf.CopyFrom(*common_flags()); - cf.print_summary = false; cf.external_symbolizer_path = GetFlag("UBSAN_SYMBOLIZER_PATH"); OverrideCommonFlags(cf); } diff --git a/libsanitizer/ubsan/ubsan_handlers.cpp b/libsanitizer/ubsan/ubsan_handlers.cpp index 6099e3631e7..3f9da75a12a 100644 --- a/libsanitizer/ubsan/ubsan_handlers.cpp +++ b/libsanitizer/ubsan/ubsan_handlers.cpp @@ -691,14 +691,33 @@ static void handlePointerOverflowImpl(PointerOverflowData *Data, ValueHandle Result, ReportOptions Opts) { SourceLocation Loc = Data->Loc.acquire(); - ErrorType ET = ErrorType::PointerOverflow; + ErrorType ET; + + if (Base == 0 && Result == 0) + ET = ErrorType::NullptrWithOffset; + else if (Base == 0 && Result != 0) + ET = ErrorType::NullptrWithNonZeroOffset; + else if (Base != 0 && Result == 0) + ET = ErrorType::NullptrAfterNonZeroOffset; + else + ET = ErrorType::PointerOverflow; if (ignoreReport(Loc, Opts, ET)) return; ScopedReport R(Opts, Loc, ET); - if ((sptr(Base) >= 0) == (sptr(Result) >= 0)) { + if (ET == ErrorType::NullptrWithOffset) { + Diag(Loc, DL_Error, ET, "applying zero offset to null pointer"); + } else if (ET == ErrorType::NullptrWithNonZeroOffset) { + Diag(Loc, DL_Error, ET, "applying non-zero offset %0 to null pointer") + << Result; + } else if (ET == ErrorType::NullptrAfterNonZeroOffset) { + Diag( + Loc, DL_Error, ET, + "applying non-zero offset to non-null pointer %0 produced null pointer") + << (void *)Base; + } else if ((sptr(Base) >= 0) == (sptr(Result) >= 0)) { if (Base > Result) Diag(Loc, DL_Error, ET, "addition of unsigned offset to %0 overflowed to %1") @@ -800,21 +819,6 @@ void __ubsan_handle_cfi_bad_type(CFICheckFailData *Data, ValueHandle Vtable, } // namespace __ubsan -void __ubsan::__ubsan_handle_cfi_bad_icall(CFIBadIcallData *CallData, - ValueHandle Function) { - GET_REPORT_OPTIONS(false); - CFICheckFailData Data = {CFITCK_ICall, CallData->Loc, CallData->Type}; - handleCFIBadIcall(&Data, Function, Opts); -} - -void __ubsan::__ubsan_handle_cfi_bad_icall_abort(CFIBadIcallData *CallData, - ValueHandle Function) { - GET_REPORT_OPTIONS(true); - CFICheckFailData Data = {CFITCK_ICall, CallData->Loc, CallData->Type}; - handleCFIBadIcall(&Data, Function, Opts); - Die(); -} - void __ubsan::__ubsan_handle_cfi_check_fail(CFICheckFailData *Data, ValueHandle Value, uptr ValidVtable) { diff --git a/libsanitizer/ubsan/ubsan_handlers.h b/libsanitizer/ubsan/ubsan_handlers.h index eba1cf918fc..22ca9642238 100644 --- a/libsanitizer/ubsan/ubsan_handlers.h +++ b/libsanitizer/ubsan/ubsan_handlers.h @@ -207,20 +207,12 @@ enum CFITypeCheckKind : unsigned char { CFITCK_VMFCall, }; -struct CFIBadIcallData { - SourceLocation Loc; - const TypeDescriptor &Type; -}; - struct CFICheckFailData { CFITypeCheckKind CheckKind; SourceLocation Loc; const TypeDescriptor &Type; }; -/// \brief Handle control flow integrity failure for indirect function calls. -RECOVERABLE(cfi_bad_icall, CFIBadIcallData *Data, ValueHandle Function) - /// \brief Handle control flow integrity failures. RECOVERABLE(cfi_check_fail, CFICheckFailData *Data, ValueHandle Function, uptr VtableIsValid) diff --git a/libsanitizer/ubsan/ubsan_platform.h b/libsanitizer/ubsan/ubsan_platform.h index 58aabbe67b5..71d7fb18c9b 100644 --- a/libsanitizer/ubsan/ubsan_platform.h +++ b/libsanitizer/ubsan/ubsan_platform.h @@ -12,7 +12,6 @@ #ifndef UBSAN_PLATFORM_H #define UBSAN_PLATFORM_H -#ifndef CAN_SANITIZE_UB // Other platforms should be easy to add, and probably work as-is. #if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || \ defined(__NetBSD__) || defined(__OpenBSD__) || \ @@ -22,6 +21,5 @@ #else # define CAN_SANITIZE_UB 0 #endif -#endif //CAN_SANITIZE_UB #endif diff --git a/libsanitizer/ubsan/ubsan_signals_standalone.cpp b/libsanitizer/ubsan/ubsan_signals_standalone.cpp index 627b3c4d89b..2c91db8ca39 100644 --- a/libsanitizer/ubsan/ubsan_signals_standalone.cpp +++ b/libsanitizer/ubsan/ubsan_signals_standalone.cpp @@ -45,8 +45,9 @@ namespace __ubsan { static void OnStackUnwind(const SignalContext &sig, const void *, BufferedStackTrace *stack) { - ubsan_GetStackTrace(stack, kStackTraceMax, sig.pc, sig.bp, sig.context, - common_flags()->fast_unwind_on_fatal); + ubsan_GetStackTrace(stack, kStackTraceMax, + StackTrace::GetNextInstructionPc(sig.pc), sig.bp, + sig.context, common_flags()->fast_unwind_on_fatal); } static void UBsanOnDeadlySignal(int signo, void *siginfo, void *context) {