authorgravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2026-08-03 13:06:07+02:00
committergravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2026-09-05 14:54:30+02:00
log6498f963bc7ecf275173b82ec4da67046116db1a
treeb8aa64edb788fd62b3a7078d5056d72d4bd55396
parent5c17ee74127366ad8cc4d4ce82f11aa51899e28a
signaturebadge-check Signed by SSH key SHA256:7B/LJ7bpR1eX8aCXSr4mtd5M45VMPKcx9zY8e95b5QM

libtsan: update to LLVM 23


55 files changed, 1399 insertions(+), 297 deletions(-)

lib/libtsan/interception/interception.h+10
......@@ -362,6 +362,16 @@ const interpose_substitution substitution_##func_name[] \
362362// so we use casts via uintptr_t (the local __sanitizer::uptr equivalent).
363363namespace __interception {
364364
365// Dynamic library loading helpers (dlopen/LoadLibrary, dlsym/GetProcAddress).
366// Implemented in interception_linux.cpp on non-Windows targets and
367// interception_win.cpp on Windows.
368bool DynamicLoaderAvailable();
369void* OpenLibrary(const char* name);
370void* LookupSymbol(void* handle, const char* symbol);
371void* LookupSymbolDefault(const char* symbol);
372void* LookupSymbolNext(const char* symbol);
373void* LookupSymbolNextVersioned(const char* symbol, const char* version);
374
365375#if defined(__ELF__) && !SANITIZER_FUCHSIA
366376// The use of interceptors makes many sanitizers unusable for static linking.
367377// Define a function, if called, will cause a linker error (undefined _DYNAMIC).
lib/libtsan/interception/interception_linux.cpp+58-5
......@@ -9,15 +9,68 @@
99// This file is a part of AddressSanitizer, an address sanity checker.
1010//
1111// Linux-specific interception methods.
12//
13// POSIX dynamic-library helpers (dlopen / dlsym) live here for every
14// non-Windows interception target (Linux, *BSD, Darwin, AIX, Fuchsia, ...).
15// macOS/AIX/Fuchsia compile this TU for RTInterception but do not use the
16// Linux-specific InterceptFunction helpers below.
1217//===----------------------------------------------------------------------===//
1318
1419#include "interception.h"
1520
21#if !SANITIZER_WINDOWS
22
23# include <dlfcn.h>
24
25# pragma weak dlopen
26# pragma weak dlsym
27#if SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD
28# pragma weak dlvsym
29#endif
30
31namespace __interception {
32
33bool DynamicLoaderAvailable() { return dlopen != nullptr && dlsym != nullptr; }
34
35void* OpenLibrary(const char* name) {
36 if (!DynamicLoaderAvailable())
37 return nullptr;
38 return dlopen(name, RTLD_LAZY | RTLD_LOCAL);
39}
40
41void* LookupSymbol(void* handle, const char* symbol) {
42 if (!DynamicLoaderAvailable())
43 return nullptr;
44 return dlsym(handle, symbol);
45}
46
47void* LookupSymbolDefault(const char* symbol) {
48 if (!DynamicLoaderAvailable())
49 return nullptr;
50 return dlsym(RTLD_DEFAULT, symbol);
51}
52
53void* LookupSymbolNext(const char* symbol) {
54 if (!DynamicLoaderAvailable())
55 return nullptr;
56 return dlsym(RTLD_NEXT, symbol);
57}
58
59#if SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD
60void* LookupSymbolNextVersioned(const char* symbol, const char* version) {
61 if (!DynamicLoaderAvailable() || dlvsym == nullptr)
62 return nullptr;
63 return dlvsym(RTLD_NEXT, symbol, version);
64}
65#endif // SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD
66
67} // namespace __interception
68
69#endif // !SANITIZER_WINDOWS
70
1671#if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || \
1772 SANITIZER_SOLARIS || SANITIZER_HAIKU
1873
19#include <dlfcn.h> // for dlsym() and dlvsym()
20
2174namespace __interception {
2275
2376#if SANITIZER_NETBSD
......@@ -39,14 +92,14 @@ static void *GetFuncAddr(const char *name, uptr trampoline) {
3992 if (StrCmp(name, "sigaction"))
4093 name = "__sigaction14";
4194#endif
42 void *addr = dlsym(RTLD_NEXT, name);
95 void* addr = LookupSymbolNext(name);
4396 if (!addr) {
4497 // If the lookup using RTLD_NEXT failed, the sanitizer runtime library is
4598 // later in the library search order than the DSO that we are trying to
4699 // intercept, which means that we cannot intercept this function. We still
47100 // want the address of the real definition, though, so look it up using
48101 // RTLD_DEFAULT.
49 addr = dlsym(RTLD_DEFAULT, name);
102 addr = LookupSymbolDefault(name);
50103
51104 // In case `name' is not loaded, dlsym ends up finding the actual wrapper.
52105 // We don't want to intercept the wrapper and have it point to itself.
......@@ -66,7 +119,7 @@ bool InterceptFunction(const char *name, uptr *ptr_to_real, uptr func,
66119// dlvsym is a GNU extension supported by some other platforms.
67120#if SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD
68121static void *GetFuncAddr(const char *name, const char *ver) {
69 return dlvsym(RTLD_NEXT, name, ver);
122 return LookupSymbolNextVersioned(name, ver);
70123}
71124
72125bool InterceptFunction(const char *name, const char *ver, uptr *ptr_to_real,
lib/libtsan/interception/interception_win.cpp+25
......@@ -134,6 +134,30 @@
134134
135135namespace __interception {
136136
137bool DynamicLoaderAvailable() { return true; }
138
139void* OpenLibrary(const char* name) {
140 if (!name)
141 return reinterpret_cast<void*>(GetModuleHandleA(nullptr));
142 return reinterpret_cast<void*>(LoadLibraryA(name));
143}
144
145void* LookupSymbol(void* handle, const char* symbol) {
146 if (!handle)
147 return nullptr;
148 return reinterpret_cast<void*>(reinterpret_cast<__sanitizer::uptr>(
149 GetProcAddress(reinterpret_cast<HMODULE>(handle), symbol)));
150}
151
152void* LookupSymbolDefault(const char* symbol) {
153 return LookupSymbol(reinterpret_cast<void*>(GetModuleHandleA(nullptr)),
154 symbol);
155}
156
157void* LookupSymbolNext(const char*) { return nullptr; }
158
159void* LookupSymbolNextVersioned(const char*, const char*) { return nullptr; }
160
137161static const int kAddressLength = FIRST_32_SECOND_64(4, 8);
138162static const int kJumpInstructionLength = 5;
139163static const int kShortJumpInstructionLength = 2;
......@@ -655,6 +679,7 @@ static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) {
655679 return 2;
656680
657681 case 0x3980: // 80 39 XX : cmp BYTE PTR [rcx], XX
682 case 0x3a80: // 80 3A XX : cmp BYTE PTR [rdx], XX
658683 case 0x4D8B: // 8B 4D XX : mov XX(%ebp), ecx
659684 case 0x558B: // 8B 55 XX : mov XX(%ebp), edx
660685 case 0x758B: // 8B 75 XX : mov XX(%ebp), esp
lib/libtsan/sanitizer_common/sanitizer_allocator.cpp+3-2
......@@ -109,14 +109,15 @@ void *InternalReallocArray(void *addr, uptr count, uptr size,
109109 return InternalRealloc(addr, count * size, cache);
110110}
111111
112void *InternalCalloc(uptr count, uptr size, InternalAllocatorCache *cache) {
112void* InternalCalloc(uptr count, uptr size, InternalAllocatorCache* cache,
113 uptr alignment) {
113114 if (UNLIKELY(CheckForCallocOverflow(count, size))) {
114115 Report("FATAL: %s: calloc parameters overflow: count * size (%zd * %zd) "
115116 "cannot be represented in type size_t\n", SanitizerToolName, count,
116117 size);
117118 Die();
118119 }
119 void *p = InternalAlloc(count * size, cache);
120 void* p = InternalAlloc(count * size, cache, alignment);
120121 if (LIKELY(p))
121122 internal_memset(p, 0, count * size);
122123 return p;
lib/libtsan/sanitizer_common/sanitizer_allocator.h-6
......@@ -47,12 +47,6 @@ void PrintHintAllocatorCannotReturnNull();
4747// Callback type for iterating over chunks.
4848typedef void (*ForEachChunkCallback)(uptr chunk, void *arg);
4949
50inline u32 Rand(u32 *state) { // ANSI C linear congruential PRNG.
51 return (*state = *state * 1103515245 + 12345) >> 16;
52}
53
54inline u32 RandN(u32 *state, u32 n) { return Rand(state) % n; } // [0, n)
55
5650template<typename T>
5751inline void RandomShuffle(T *a, u32 n, u32 *rand_state) {
5852 if (n <= 1) return;
lib/libtsan/sanitizer_common/sanitizer_allocator_dlsym.h+5-5
......@@ -40,8 +40,8 @@ struct DlSymAllocator {
4040 return ptr;
4141 }
4242
43 static void *Callocate(usize nmemb, usize size) {
44 void *ptr = InternalCalloc(nmemb, size);
43 static void* Callocate(usize nmemb, usize size, uptr align = kWordSize) {
44 void* ptr = InternalCalloc(nmemb, size, nullptr, align);
4545 CHECK(internal_allocator()->FromPrimary(ptr));
4646 Details::OnAllocate(ptr, GetSize(ptr));
4747 return ptr;
......@@ -53,9 +53,9 @@ struct DlSymAllocator {
5353 InternalFree(ptr);
5454 }
5555
56 static void *Realloc(void *ptr, uptr new_size) {
56 static void* Realloc(void* ptr, uptr new_size, uptr align = kWordSize) {
5757 if (!ptr)
58 return Allocate(new_size);
58 return Allocate(new_size, align);
5959 CHECK(internal_allocator()->FromPrimary(ptr));
6060 if (!new_size) {
6161 Free(ptr);
......@@ -63,7 +63,7 @@ struct DlSymAllocator {
6363 }
6464 uptr size = GetSize(ptr);
6565 uptr memcpy_size = Min(new_size, size);
66 void *new_ptr = Allocate(new_size);
66 void* new_ptr = Allocate(new_size, align);
6767 if (new_ptr)
6868 internal_memcpy(new_ptr, ptr, memcpy_size);
6969 Free(ptr);
lib/libtsan/sanitizer_common/sanitizer_allocator_internal.h+3-2
......@@ -45,8 +45,9 @@ void *InternalRealloc(void *p, uptr size,
4545 InternalAllocatorCache *cache = nullptr);
4646void *InternalReallocArray(void *p, uptr count, uptr size,
4747 InternalAllocatorCache *cache = nullptr);
48void *InternalCalloc(uptr count, uptr size,
49 InternalAllocatorCache *cache = nullptr);
48void* InternalCalloc(uptr count, uptr size,
49 InternalAllocatorCache* cache = nullptr,
50 uptr alignment = 0);
5051void InternalFree(void *p, InternalAllocatorCache *cache = nullptr);
5152void InternalAllocatorLock();
5253void InternalAllocatorUnlock();
lib/libtsan/sanitizer_common/sanitizer_asm.h+4-2
......@@ -61,6 +61,8 @@
6161# define ASM_TAIL_CALL jg
6262#elif defined(__riscv)
6363# define ASM_TAIL_CALL tail
64#elif defined(__hexagon__)
65# define ASM_TAIL_CALL jump
6466#endif
6567
6668// Currently, almost all of the shared libraries rely on the value of
......@@ -103,8 +105,8 @@
103105# define ASM_SIZE(symbol) .size symbol, .-symbol
104106# define ASM_SYMBOL(symbol) symbol
105107# define ASM_SYMBOL_INTERCEPTOR(symbol) symbol
106# if defined(__i386__) || defined(__powerpc__) || defined(__s390__) || \
107 defined(__sparc__)
108# if defined(__i386__) || defined(__powerpc__) || defined(__s390__) || \
109 defined(__sparc__) || defined(__alpha__)
108110// For details, see interception.h
109111# define ASM_WRAPPER_NAME(symbol) __interceptor_##symbol
110112# define ASM_TRAMPOLINE_ALIAS(symbol, name) \
lib/libtsan/sanitizer_common/sanitizer_common.h+19-4
......@@ -387,8 +387,8 @@ void ReportDeadlySignal(const SignalContext &sig, u32 tid,
387387 const void *unwind_context);
388388
389389// Alternative signal stack (POSIX-only).
390void SetAlternateSignalStack();
391void UnsetAlternateSignalStack();
390void* SetAlternateSignalStack();
391void UnsetAlternateSignalStack(void* altstack_base);
392392
393393bool IsSignalHandlerFromSanitizer(int signum);
394394bool SetSignalHandlerFromSanitizer(int signum, bool new_state);
......@@ -906,7 +906,14 @@ class LoadedModule {
906906class ListOfModules {
907907 public:
908908 ListOfModules() : initialized(false) {}
909 ~ListOfModules() { clear(); }
909 ~ListOfModules() {
910 clear();
911 if (initialized)
912 modules_.Destroy();
913 }
914 ListOfModules(const ListOfModules&) = delete;
915 ListOfModules& operator=(const ListOfModules&) = delete;
916
910917 void init();
911918 void fallbackInit(); // Uses fallback init if available, otherwise clears
912919 const LoadedModule *begin() const { return modules_.begin(); }
......@@ -1085,7 +1092,9 @@ struct StackDepotStats {
10851092// indicate that sanitizer allocator should not attempt to release memory to OS.
10861093const s32 kReleaseToOSIntervalNever = -1;
10871094
1088void CheckNoDeepBind(const char *filename, int flag);
1095// Platform hook invoked before dlopen. Performs platform-specific dlopen flag
1096// checks (e.g. RTLD_DEEPBIND on Linux).
1097void OnDlOpen(const char* filename, int flag);
10891098
10901099// Returns the requested amount of random data (up to 256 bytes) that can then
10911100// be used to seed a PRNG. Defaults to blocking like the underlying syscall.
......@@ -1100,6 +1109,12 @@ inline u32 GetNumberOfCPUsCached() {
11001109 return NumberOfCPUsCached;
11011110}
11021111
1112inline u32 Rand(u32* state) { // ANSI C linear congruential PRNG.
1113 return (*state = *state * 1103515245 + 12345) >> 16;
1114}
1115
1116inline u32 RandN(u32* state, u32 n) { return Rand(state) % n; } // [0, n)
1117
11031118} // namespace __sanitizer
11041119
11051120inline void *operator new(__sanitizer::usize size,
lib/libtsan/sanitizer_common/sanitizer_common_interceptors.inc+65-2
......@@ -277,8 +277,11 @@ extern const short *_tolower_tab_;
277277 common_flags()->strict_string_checks ? (internal_strlen(s)) + 1 : (n) )
278278
279279#ifndef COMMON_INTERCEPTOR_DLOPEN
280#define COMMON_INTERCEPTOR_DLOPEN(filename, flag) \
281 ({ CheckNoDeepBind(filename, flag); REAL(dlopen)(filename, flag); })
280# define COMMON_INTERCEPTOR_DLOPEN(filename, flag) \
281 ({ \
282 OnDlOpen(filename, flag); \
283 REAL(dlopen)(filename, flag); \
284 })
282285#endif
283286
284287#ifndef COMMON_INTERCEPTOR_GET_TLS_RANGE
......@@ -1023,6 +1026,25 @@ INTERCEPTOR(SSIZE_T, read, int fd, void *ptr, SIZE_T count) {
10231026#define INIT_READ
10241027#endif
10251028
1029#if SANITIZER_INTERCEPT___READ_CHK
1030INTERCEPTOR(SSIZE_T, __read_chk, int fd, void* ptr, SIZE_T count,
1031 SIZE_T buflen) {
1032 void* ctx;
1033 COMMON_INTERCEPTOR_ENTER(ctx, __read_chk, fd, ptr, count, buflen);
1034 COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
1035 SSIZE_T res =
1036 COMMON_INTERCEPTOR_BLOCK_REAL(__read_chk)(fd, ptr, count, buflen);
1037 if (res > 0)
1038 COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, res);
1039 if (res >= 0 && fd >= 0)
1040 COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
1041 return res;
1042}
1043# define INIT___READ_CHK COMMON_INTERCEPT_FUNCTION(__read_chk)
1044#else
1045# define INIT___READ_CHK
1046#endif
1047
10261048#if SANITIZER_INTERCEPT_FREAD
10271049INTERCEPTOR(SIZE_T, fread, void *ptr, SIZE_T size, SIZE_T nmemb, void *file) {
10281050 // libc file streams can call user-supplied functions, see fopencookie.
......@@ -1058,6 +1080,25 @@ INTERCEPTOR(SSIZE_T, pread, int fd, void *ptr, SIZE_T count, OFF_T offset) {
10581080#define INIT_PREAD
10591081#endif
10601082
1083#if SANITIZER_INTERCEPT___PREAD_CHK
1084INTERCEPTOR(SSIZE_T, __pread_chk, int fd, void* ptr, SIZE_T count, OFF_T offset,
1085 SIZE_T buflen) {
1086 void* ctx;
1087 COMMON_INTERCEPTOR_ENTER(ctx, __pread_chk, fd, ptr, count, offset, buflen);
1088 COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
1089 SSIZE_T res = COMMON_INTERCEPTOR_BLOCK_REAL(__pread_chk)(fd, ptr, count,
1090 offset, buflen);
1091 if (res > 0)
1092 COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, res);
1093 if (res >= 0 && fd >= 0)
1094 COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
1095 return res;
1096}
1097# define INIT___PREAD_CHK COMMON_INTERCEPT_FUNCTION(__pread_chk)
1098#else
1099# define INIT___PREAD_CHK
1100#endif
1101
10611102#if SANITIZER_INTERCEPT_PREAD64
10621103INTERCEPTOR(SSIZE_T, pread64, int fd, void *ptr, SIZE_T count, OFF64_T offset) {
10631104 void *ctx;
......@@ -1076,6 +1117,25 @@ INTERCEPTOR(SSIZE_T, pread64, int fd, void *ptr, SIZE_T count, OFF64_T offset) {
10761117#define INIT_PREAD64
10771118#endif
10781119
1120#if SANITIZER_INTERCEPT___PREAD64_CHK
1121INTERCEPTOR(SSIZE_T, __pread64_chk, int fd, void* ptr, SIZE_T count,
1122 OFF64_T offset, SIZE_T buflen) {
1123 void* ctx;
1124 COMMON_INTERCEPTOR_ENTER(ctx, __pread64_chk, fd, ptr, count, offset, buflen);
1125 COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
1126 SSIZE_T res = COMMON_INTERCEPTOR_BLOCK_REAL(__pread64_chk)(fd, ptr, count,
1127 offset, buflen);
1128 if (res > 0)
1129 COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, res);
1130 if (res >= 0 && fd >= 0)
1131 COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
1132 return res;
1133}
1134# define INIT___PREAD64_CHK COMMON_INTERCEPT_FUNCTION(__pread64_chk)
1135#else
1136# define INIT___PREAD64_CHK
1137#endif
1138
10791139#if SANITIZER_INTERCEPT_READV
10801140INTERCEPTOR_WITH_SUFFIX(SSIZE_T, readv, int fd, __sanitizer_iovec *iov,
10811141 int iovcnt) {
......@@ -10428,9 +10488,12 @@ static void InitializeCommonInterceptors() {
1042810488 INIT_MEMRCHR;
1042910489 INIT_MEMMEM;
1043010490 INIT_READ;
10491 INIT___READ_CHK;
1043110492 INIT_FREAD;
1043210493 INIT_PREAD;
10494 INIT___PREAD_CHK;
1043310495 INIT_PREAD64;
10496 INIT___PREAD64_CHK;
1043410497 INIT_READV;
1043510498 INIT_PREADV;
1043610499 INIT_PREADV64;
lib/libtsan/sanitizer_common/sanitizer_common_interface.inc-1
......@@ -10,7 +10,6 @@
1010INTERFACE_FUNCTION(__sanitizer_acquire_crash_state)
1111INTERFACE_FUNCTION(__sanitizer_annotate_contiguous_container)
1212INTERFACE_FUNCTION(__sanitizer_annotate_double_ended_contiguous_container)
13INTERFACE_FUNCTION(__sanitizer_copy_contiguous_container_annotations)
1413INTERFACE_FUNCTION(__sanitizer_contiguous_container_find_bad_address)
1514INTERFACE_FUNCTION(
1615 __sanitizer_double_ended_contiguous_container_find_bad_address)
lib/libtsan/sanitizer_common/sanitizer_dense_map.h+57-95
......@@ -44,10 +44,10 @@ class DenseMapBase {
4444 }
4545
4646 void clear() {
47 if (getNumEntries() == 0 && getNumTombstones() == 0)
47 if (getNumEntries() == 0)
4848 return;
4949
50 const KeyT EmptyKey = getEmptyKey(), TombstoneKey = getTombstoneKey();
50 const KeyT EmptyKey = getEmptyKey();
5151 if (__sanitizer::is_trivially_destructible<ValueT>::value) {
5252 // Use a simpler loop when values don't need destruction.
5353 for (BucketT *P = getBuckets(), *E = getBucketsEnd(); P != E; ++P)
......@@ -56,17 +56,14 @@ class DenseMapBase {
5656 unsigned NumEntries = getNumEntries();
5757 for (BucketT *P = getBuckets(), *E = getBucketsEnd(); P != E; ++P) {
5858 if (!KeyInfoT::isEqual(P->getFirst(), EmptyKey)) {
59 if (!KeyInfoT::isEqual(P->getFirst(), TombstoneKey)) {
60 P->getSecond().~ValueT();
61 --NumEntries;
62 }
59 P->getSecond().~ValueT();
60 --NumEntries;
6361 P->getFirst() = EmptyKey;
6462 }
6563 }
6664 CHECK_EQ(NumEntries, 0);
6765 }
6866 setNumEntries(0);
69 setNumTombstones(0);
7067 }
7168
7269 /// Return true if the specified key is in the map, false otherwise.
......@@ -171,20 +168,13 @@ class DenseMapBase {
171168 if (!TheBucket)
172169 return false; // not in map.
173170
174 TheBucket->getSecond().~ValueT();
175 TheBucket->getFirst() = getTombstoneKey();
176 decrementNumEntries();
177 incrementNumTombstones();
171 eraseFromFilledBucket(TheBucket);
178172 return true;
179173 }
180174
181175 void erase(value_type *I) {
182176 CHECK_NE(I, nullptr);
183 BucketT *TheBucket = &*I;
184 TheBucket->getSecond().~ValueT();
185 TheBucket->getFirst() = getTombstoneKey();
186 decrementNumEntries();
187 incrementNumTombstones();
177 eraseFromFilledBucket(I);
188178 }
189179
190180 value_type &FindAndConstruct(const KeyT &Key) {
......@@ -214,11 +204,10 @@ class DenseMapBase {
214204 /// Function can return fast to stop the process.
215205 template <class Fn>
216206 void forEach(Fn fn) {
217 const KeyT EmptyKey = getEmptyKey(), TombstoneKey = getTombstoneKey();
207 const KeyT EmptyKey = getEmptyKey();
218208 for (auto *P = getBuckets(), *E = getBucketsEnd(); P != E; ++P) {
219209 const KeyT K = P->getFirst();
220 if (!KeyInfoT::isEqual(K, EmptyKey) &&
221 !KeyInfoT::isEqual(K, TombstoneKey)) {
210 if (!KeyInfoT::isEqual(K, EmptyKey)) {
222211 if (!fn(*P))
223212 return;
224213 }
......@@ -238,10 +227,9 @@ class DenseMapBase {
238227 if (getNumBuckets() == 0) // Nothing to do.
239228 return;
240229
241 const KeyT EmptyKey = getEmptyKey(), TombstoneKey = getTombstoneKey();
230 const KeyT EmptyKey = getEmptyKey();
242231 for (BucketT *P = getBuckets(), *E = getBucketsEnd(); P != E; ++P) {
243 if (!KeyInfoT::isEqual(P->getFirst(), EmptyKey) &&
244 !KeyInfoT::isEqual(P->getFirst(), TombstoneKey))
232 if (!KeyInfoT::isEqual(P->getFirst(), EmptyKey))
245233 P->getSecond().~ValueT();
246234 P->getFirst().~KeyT();
247235 }
......@@ -249,7 +237,6 @@ class DenseMapBase {
249237
250238 void initEmpty() {
251239 setNumEntries(0);
252 setNumTombstones(0);
253240
254241 CHECK_EQ((getNumBuckets() & (getNumBuckets() - 1)), 0);
255242 const KeyT EmptyKey = getEmptyKey();
......@@ -273,10 +260,8 @@ class DenseMapBase {
273260
274261 // Insert all the old elements.
275262 const KeyT EmptyKey = getEmptyKey();
276 const KeyT TombstoneKey = getTombstoneKey();
277263 for (BucketT *B = OldBucketsBegin, *E = OldBucketsEnd; B != E; ++B) {
278 if (!KeyInfoT::isEqual(B->getFirst(), EmptyKey) &&
279 !KeyInfoT::isEqual(B->getFirst(), TombstoneKey)) {
264 if (!KeyInfoT::isEqual(B->getFirst(), EmptyKey)) {
280265 // Insert the key/value into the new table.
281266 BucketT *DestBucket;
282267 bool FoundVal = LookupBucketFor(B->getFirst(), DestBucket);
......@@ -301,7 +286,6 @@ class DenseMapBase {
301286 CHECK_EQ(getNumBuckets(), other.getNumBuckets());
302287
303288 setNumEntries(other.getNumEntries());
304 setNumTombstones(other.getNumTombstones());
305289
306290 if (__sanitizer::is_trivially_copyable<KeyT>::value &&
307291 __sanitizer::is_trivially_copyable<ValueT>::value)
......@@ -311,8 +295,7 @@ class DenseMapBase {
311295 for (uptr i = 0; i < getNumBuckets(); ++i) {
312296 ::new (&getBuckets()[i].getFirst())
313297 KeyT(other.getBuckets()[i].getFirst());
314 if (!KeyInfoT::isEqual(getBuckets()[i].getFirst(), getEmptyKey()) &&
315 !KeyInfoT::isEqual(getBuckets()[i].getFirst(), getTombstoneKey()))
298 if (!KeyInfoT::isEqual(getBuckets()[i].getFirst(), getEmptyKey()))
316299 ::new (&getBuckets()[i].getSecond())
317300 ValueT(other.getBuckets()[i].getSecond());
318301 }
......@@ -329,9 +312,40 @@ class DenseMapBase {
329312
330313 static const KeyT getEmptyKey() { return KeyInfoT::getEmptyKey(); }
331314
332 static const KeyT getTombstoneKey() { return KeyInfoT::getTombstoneKey(); }
333
334315 private:
316 /// Erase the entry at \p TheBucket and close the resulting hole via Knuth
317 /// TAOCP 6.4 Algorithm R: walk forward over the cluster, shifting back any
318 /// entry whose linear-probe chain from its home bucket passes through the
319 /// hole, until an empty bucket terminates the cluster.
320 void eraseFromFilledBucket(BucketT* TheBucket) {
321 TheBucket->getSecond().~ValueT();
322 decrementNumEntries();
323
324 BucketT* BucketsPtr = getBuckets();
325 const unsigned NumBuckets = getNumBuckets();
326 const unsigned Mask = NumBuckets - 1;
327 const KeyT EmptyKey = getEmptyKey();
328 unsigned I = static_cast<unsigned>(TheBucket - BucketsPtr);
329 unsigned J = I;
330 while (true) {
331 J = (J + 1) & Mask;
332 BucketT& BJ = BucketsPtr[J];
333 if (KeyInfoT::isEqual(BJ.getFirst(), EmptyKey))
334 break;
335 unsigned Ideal = getHashValue(BJ.getFirst()) & Mask;
336 // If the hole (I) lies on the linear-probe chain from the home bucket
337 // (Ideal) to J, shift J into the hole and make J the new hole.
338 if (((I - Ideal) & Mask) < ((J - Ideal) & Mask)) {
339 BucketT& BI = BucketsPtr[I];
340 BI.getFirst() = __sanitizer::move(BJ.getFirst());
341 ::new (&BI.getSecond()) ValueT(__sanitizer::move(BJ.getSecond()));
342 BJ.getSecond().~ValueT();
343 I = J;
344 }
345 }
346 BucketsPtr[I].getFirst() = EmptyKey;
347 }
348
335349 unsigned getNumEntries() const {
336350 return static_cast<const DerivedT *>(this)->getNumEntries();
337351 }
......@@ -344,18 +358,6 @@ class DenseMapBase {
344358
345359 void decrementNumEntries() { setNumEntries(getNumEntries() - 1); }
346360
347 unsigned getNumTombstones() const {
348 return static_cast<const DerivedT *>(this)->getNumTombstones();
349 }
350
351 void setNumTombstones(unsigned Num) {
352 static_cast<DerivedT *>(this)->setNumTombstones(Num);
353 }
354
355 void incrementNumTombstones() { setNumTombstones(getNumTombstones() + 1); }
356
357 void decrementNumTombstones() { setNumTombstones(getNumTombstones() - 1); }
358
359361 const BucketT *getBuckets() const {
360362 return static_cast<const DerivedT *>(this)->getBuckets();
361363 }
......@@ -398,25 +400,16 @@ class DenseMapBase {
398400 template <typename LookupKeyT>
399401 BucketT *InsertIntoBucketImpl(const KeyT &Key, const LookupKeyT &Lookup,
400402 BucketT *TheBucket) {
401 // If the load of the hash table is more than 3/4, or if fewer than 1/8 of
402 // the buckets are empty (meaning that many are filled with tombstones),
403 // grow the table.
404 //
405 // The later case is tricky. For example, if we had one empty bucket with
406 // tons of tombstones, failing lookups (e.g. for insertion) would have to
407 // probe almost the entire table until it found the empty bucket. If the
408 // table completely filled with tombstones, no lookup would ever succeed,
409 // causing infinite loops in lookup.
403 // Grow the table if the load factor would exceed 3/4 after insertion.
404 // Linear probing with gap-closing deletion (Knuth Algorithm R) keeps every
405 // chain compact and bounded by the table's empty-bucket count, so no
406 // tombstone-driven resize is needed.
410407 unsigned NewNumEntries = getNumEntries() + 1;
411408 unsigned NumBuckets = getNumBuckets();
412409 if (UNLIKELY(NewNumEntries * 4 >= NumBuckets * 3)) {
413410 this->grow(NumBuckets * 2);
414411 LookupBucketFor(Lookup, TheBucket);
415412 NumBuckets = getNumBuckets();
416 } else if (UNLIKELY(NumBuckets - (NewNumEntries + getNumTombstones()) <=
417 NumBuckets / 8)) {
418 this->grow(NumBuckets);
419 LookupBucketFor(Lookup, TheBucket);
420413 }
421414 CHECK(TheBucket);
422415
......@@ -424,11 +417,6 @@ class DenseMapBase {
424417 // so that when growing buckets we have self-consistent entry count.
425418 incrementNumEntries();
426419
427 // If we are writing over a tombstone, remember this.
428 const KeyT EmptyKey = getEmptyKey();
429 if (!KeyInfoT::isEqual(TheBucket->getFirst(), EmptyKey))
430 decrementNumTombstones();
431
432420 return TheBucket;
433421 }
434422
......@@ -441,7 +429,6 @@ class DenseMapBase {
441429
442430 const KeyT EmptyKey = getEmptyKey();
443431 unsigned BucketNo = getHashValue(Val) & (NumBuckets - 1);
444 unsigned ProbeAmt = 1;
445432 while (true) {
446433 BucketT *Bucket = BucketsPtr + BucketNo;
447434 if (LIKELY(KeyInfoT::isEqual(Val, Bucket->getFirst())))
......@@ -449,10 +436,8 @@ class DenseMapBase {
449436 if (LIKELY(KeyInfoT::isEqual(Bucket->getFirst(), EmptyKey)))
450437 return nullptr;
451438
452 // Otherwise, it's a hash collision or a tombstone, continue quadratic
453 // probing.
454 BucketNo += ProbeAmt++;
455 BucketNo &= NumBuckets - 1;
439 // Hash collision: continue linear probing.
440 BucketNo = (BucketNo + 1) & (NumBuckets - 1);
456441 }
457442 }
458443
......@@ -463,8 +448,8 @@ class DenseMapBase {
463448
464449 /// LookupBucketFor - Lookup the appropriate bucket for Val, returning it in
465450 /// FoundBucket. If the bucket contains the key and a value, this returns
466 /// true, otherwise it returns a bucket with an empty marker or tombstone and
467 /// returns false.
451 /// true, otherwise it returns a bucket with an empty marker and returns
452 /// false.
468453 template <typename LookupKeyT>
469454 bool LookupBucketFor(const LookupKeyT &Val,
470455 const BucketT *&FoundBucket) const {
......@@ -476,15 +461,10 @@ class DenseMapBase {
476461 return false;
477462 }
478463
479 // FoundTombstone - Keep track of whether we find a tombstone while probing.
480 const BucketT *FoundTombstone = nullptr;
481464 const KeyT EmptyKey = getEmptyKey();
482 const KeyT TombstoneKey = getTombstoneKey();
483465 CHECK(!KeyInfoT::isEqual(Val, EmptyKey));
484 CHECK(!KeyInfoT::isEqual(Val, TombstoneKey));
485466
486467 unsigned BucketNo = getHashValue(Val) & (NumBuckets - 1);
487 unsigned ProbeAmt = 1;
488468 while (true) {
489469 const BucketT *ThisBucket = BucketsPtr + BucketNo;
490470 // Found Val's bucket? If so, return it.
......@@ -494,24 +474,14 @@ class DenseMapBase {
494474 }
495475
496476 // If we found an empty bucket, the key doesn't exist in the set.
497 // Insert it and return the default value.
477 // Return it as the insertion point.
498478 if (LIKELY(KeyInfoT::isEqual(ThisBucket->getFirst(), EmptyKey))) {
499 // If we've already seen a tombstone while probing, fill it in instead
500 // of the empty bucket we eventually probed to.
501 FoundBucket = FoundTombstone ? FoundTombstone : ThisBucket;
479 FoundBucket = ThisBucket;
502480 return false;
503481 }
504482
505 // If this is a tombstone, remember it. If Val ends up not in the map, we
506 // prefer to return it than something that would require more probing.
507 if (KeyInfoT::isEqual(ThisBucket->getFirst(), TombstoneKey) &&
508 !FoundTombstone)
509 FoundTombstone = ThisBucket; // Remember the first tombstone found.
510
511 // Otherwise, it's a hash collision or a tombstone, continue quadratic
512 // probing.
513 BucketNo += ProbeAmt++;
514 BucketNo &= (NumBuckets - 1);
483 // Hash collision: continue linear probing.
484 BucketNo = (BucketNo + 1) & (NumBuckets - 1);
515485 }
516486 }
517487
......@@ -587,7 +557,6 @@ class DenseMap : public DenseMapBase<DenseMap<KeyT, ValueT, KeyInfoT, BucketT>,
587557
588558 BucketT *Buckets = nullptr;
589559 unsigned NumEntries = 0;
590 unsigned NumTombstones = 0;
591560 unsigned NumBuckets = 0;
592561
593562 public:
......@@ -614,7 +583,6 @@ class DenseMap : public DenseMapBase<DenseMap<KeyT, ValueT, KeyInfoT, BucketT>,
614583 void swap(DenseMap &RHS) {
615584 Swap(Buckets, RHS.Buckets);
616585 Swap(NumEntries, RHS.NumEntries);
617 Swap(NumTombstones, RHS.NumTombstones);
618586 Swap(NumBuckets, RHS.NumBuckets);
619587 }
620588
......@@ -639,7 +607,6 @@ class DenseMap : public DenseMapBase<DenseMap<KeyT, ValueT, KeyInfoT, BucketT>,
639607 this->BaseT::copyFrom(other);
640608 } else {
641609 NumEntries = 0;
642 NumTombstones = 0;
643610 }
644611 }
645612
......@@ -649,7 +616,6 @@ class DenseMap : public DenseMapBase<DenseMap<KeyT, ValueT, KeyInfoT, BucketT>,
649616 this->BaseT::initEmpty();
650617 } else {
651618 NumEntries = 0;
652 NumTombstones = 0;
653619 }
654620 }
655621
......@@ -675,10 +641,6 @@ class DenseMap : public DenseMapBase<DenseMap<KeyT, ValueT, KeyInfoT, BucketT>,
675641
676642 void setNumEntries(unsigned Num) { NumEntries = Num; }
677643
678 unsigned getNumTombstones() const { return NumTombstones; }
679
680 void setNumTombstones(unsigned Num) { NumTombstones = Num; }
681
682644 BucketT *getBuckets() const { return Buckets; }
683645
684646 unsigned getNumBuckets() const { return NumBuckets; }
lib/libtsan/sanitizer_common/sanitizer_dense_map_info.h-25
......@@ -62,7 +62,6 @@ struct DenseMapPair {
6262template <typename T>
6363struct DenseMapInfo {
6464 // static T getEmptyKey();
65 // static T getTombstoneKey();
6665 // static unsigned getHashValue(const T &Val);
6766 // static bool isEqual(const T &LHS, const T &RHS);
6867};
......@@ -86,12 +85,6 @@ struct DenseMapInfo<T *> {
8685 return reinterpret_cast<T *>(Val);
8786 }
8887
89 static constexpr T *getTombstoneKey() {
90 uptr Val = static_cast<uptr>(-2);
91 Val <<= Log2MaxAlign;
92 return reinterpret_cast<T *>(Val);
93 }
94
9588 static constexpr unsigned getHashValue(const T *PtrVal) {
9689 return (unsigned((uptr)PtrVal) >> 4) ^ (unsigned((uptr)PtrVal) >> 9);
9790 }
......@@ -105,7 +98,6 @@ struct DenseMapInfo<T *> {
10598template <>
10699struct DenseMapInfo<char> {
107100 static constexpr char getEmptyKey() { return ~0; }
108 static constexpr char getTombstoneKey() { return ~0 - 1; }
109101 static constexpr unsigned getHashValue(const char &Val) { return Val * 37U; }
110102
111103 static constexpr bool isEqual(const char &LHS, const char &RHS) {
......@@ -117,7 +109,6 @@ struct DenseMapInfo<char> {
117109template <>
118110struct DenseMapInfo<unsigned char> {
119111 static constexpr unsigned char getEmptyKey() { return ~0; }
120 static constexpr unsigned char getTombstoneKey() { return ~0 - 1; }
121112 static constexpr unsigned getHashValue(const unsigned char &Val) {
122113 return Val * 37U;
123114 }
......@@ -132,7 +123,6 @@ struct DenseMapInfo<unsigned char> {
132123template <>
133124struct DenseMapInfo<unsigned short> {
134125 static constexpr unsigned short getEmptyKey() { return 0xFFFF; }
135 static constexpr unsigned short getTombstoneKey() { return 0xFFFF - 1; }
136126 static constexpr unsigned getHashValue(const unsigned short &Val) {
137127 return Val * 37U;
138128 }
......@@ -147,7 +137,6 @@ struct DenseMapInfo<unsigned short> {
147137template <>
148138struct DenseMapInfo<unsigned> {
149139 static constexpr unsigned getEmptyKey() { return ~0U; }
150 static constexpr unsigned getTombstoneKey() { return ~0U - 1; }
151140 static constexpr unsigned getHashValue(const unsigned &Val) {
152141 return Val * 37U;
153142 }
......@@ -161,7 +150,6 @@ struct DenseMapInfo<unsigned> {
161150template <>
162151struct DenseMapInfo<unsigned long> {
163152 static constexpr unsigned long getEmptyKey() { return ~0UL; }
164 static constexpr unsigned long getTombstoneKey() { return ~0UL - 1L; }
165153
166154 static constexpr unsigned getHashValue(const unsigned long &Val) {
167155 return (unsigned)(Val * 37UL);
......@@ -177,7 +165,6 @@ struct DenseMapInfo<unsigned long> {
177165template <>
178166struct DenseMapInfo<unsigned long long> {
179167 static constexpr unsigned long long getEmptyKey() { return ~0ULL; }
180 static constexpr unsigned long long getTombstoneKey() { return ~0ULL - 1ULL; }
181168
182169 static constexpr unsigned getHashValue(const unsigned long long &Val) {
183170 return (unsigned)(Val * 37ULL);
......@@ -193,7 +180,6 @@ struct DenseMapInfo<unsigned long long> {
193180template <>
194181struct DenseMapInfo<short> {
195182 static constexpr short getEmptyKey() { return 0x7FFF; }
196 static constexpr short getTombstoneKey() { return -0x7FFF - 1; }
197183 static constexpr unsigned getHashValue(const short &Val) { return Val * 37U; }
198184 static constexpr bool isEqual(const short &LHS, const short &RHS) {
199185 return LHS == RHS;
......@@ -204,7 +190,6 @@ struct DenseMapInfo<short> {
204190template <>
205191struct DenseMapInfo<int> {
206192 static constexpr int getEmptyKey() { return 0x7fffffff; }
207 static constexpr int getTombstoneKey() { return -0x7fffffff - 1; }
208193 static constexpr unsigned getHashValue(const int &Val) {
209194 return (unsigned)(Val * 37U);
210195 }
......@@ -221,8 +206,6 @@ struct DenseMapInfo<long> {
221206 return (1UL << (sizeof(long) * 8 - 1)) - 1UL;
222207 }
223208
224 static constexpr long getTombstoneKey() { return getEmptyKey() - 1L; }
225
226209 static constexpr unsigned getHashValue(const long &Val) {
227210 return (unsigned)(Val * 37UL);
228211 }
......@@ -236,9 +219,6 @@ struct DenseMapInfo<long> {
236219template <>
237220struct DenseMapInfo<long long> {
238221 static constexpr long long getEmptyKey() { return 0x7fffffffffffffffLL; }
239 static constexpr long long getTombstoneKey() {
240 return -0x7fffffffffffffffLL - 1;
241 }
242222
243223 static constexpr unsigned getHashValue(const long long &Val) {
244224 return (unsigned)(Val * 37ULL);
......@@ -261,11 +241,6 @@ struct DenseMapInfo<detail::DenseMapPair<T, U>> {
261241 SecondInfo::getEmptyKey());
262242 }
263243
264 static constexpr Pair getTombstoneKey() {
265 return detail::DenseMapPair<T, U>(FirstInfo::getTombstoneKey(),
266 SecondInfo::getTombstoneKey());
267 }
268
269244 static constexpr unsigned getHashValue(const Pair &PairVal) {
270245 return detail::combineHashValue(FirstInfo::getHashValue(PairVal.first),
271246 SecondInfo::getHashValue(PairVal.second));
lib/libtsan/sanitizer_common/sanitizer_errno.h+2
......@@ -31,6 +31,8 @@
3131# define __errno_location _errno
3232#elif SANITIZER_HAIKU
3333# define __errno_location _errnop
34#elif SANITIZER_AIX
35# define __errno_location _Errno
3436#endif
3537
3638extern "C" int *__errno_location();
lib/libtsan/sanitizer_common/sanitizer_flag_parser.h+2-2
......@@ -189,8 +189,8 @@ class FlagParser {
189189};
190190
191191template <typename T>
192static void RegisterFlag(FlagParser *parser, const char *name, const char *desc,
193 T *var) {
192void RegisterFlag(FlagParser* parser, const char* name, const char* desc,
193 T* var) {
194194 FlagHandler<T> *fh = new (GetGlobalLowLevelAllocator()) FlagHandler<T>(var);
195195 parser->RegisterHandler(name, fh, desc);
196196}
lib/libtsan/sanitizer_common/sanitizer_fuchsia.cpp+2-2
......@@ -93,8 +93,8 @@ void CheckMPROTECT() {}
9393void PlatformPrepareForSandboxing(void *args) {}
9494void DisableCoreDumperIfNecessary() {}
9595void InstallDeadlySignalHandlers(SignalHandlerType handler) {}
96void SetAlternateSignalStack() {}
97void UnsetAlternateSignalStack() {}
96void* SetAlternateSignalStack() { return nullptr; }
97void UnsetAlternateSignalStack(void* altstack_base) {}
9898
9999bool SignalContext::IsStackOverflow() const { return false; }
100100void SignalContext::DumpAllRegisters(void *context) { UNIMPLEMENTED(); }
lib/libtsan/sanitizer_common/sanitizer_haiku.cpp+4
......@@ -128,6 +128,10 @@ uptr internal_close(fd_t fd) {
128128 RETURN_AND_SET_ERRNO(_kern_close(fd));
129129}
130130
131uptr internal_close_range(fd_t lowfd, fd_t highfd, int flags) {
132 return -1; // Not supported.
133}
134
131135uptr internal_open(const char *filename, int flags) {
132136 CHECK(&_kern_open);
133137 RETURN_AND_SET_ERRNO(_kern_open(-1, filename, flags, 0));
lib/libtsan/sanitizer_common/sanitizer_interface_internal.h-5
......@@ -76,11 +76,6 @@ void __sanitizer_annotate_double_ended_contiguous_container(
7676 const void *old_container_beg, const void *old_container_end,
7777 const void *new_container_beg, const void *new_container_end);
7878SANITIZER_INTERFACE_ATTRIBUTE
79void __sanitizer_copy_contiguous_container_annotations(const void *src_begin,
80 const void *src_end,
81 const void *dst_begin,
82 const void *dst_end);
83SANITIZER_INTERFACE_ATTRIBUTE
8479int __sanitizer_verify_contiguous_container(const void *beg, const void *mid,
8580 const void *end);
8681SANITIZER_INTERFACE_ATTRIBUTE
lib/libtsan/sanitizer_common/sanitizer_internal_defs.h+16-12
......@@ -29,20 +29,24 @@
2929
3030// Only use SANITIZER_*ATTRIBUTE* before the function return type!
3131#if SANITIZER_WINDOWS
32#if SANITIZER_IMPORT_INTERFACE
33# define SANITIZER_INTERFACE_ATTRIBUTE __declspec(dllimport)
34#else
35# define SANITIZER_INTERFACE_ATTRIBUTE __declspec(dllexport)
36#endif
37# define SANITIZER_WEAK_ATTRIBUTE
38# define SANITIZER_WEAK_IMPORT
39#elif SANITIZER_GO
40# define SANITIZER_INTERFACE_ATTRIBUTE
41# define SANITIZER_WEAK_ATTRIBUTE
32# if SANITIZER_IMPORT_INTERFACE
33# define SANITIZER_INTERFACE_ATTRIBUTE __declspec(dllimport)
34# else
35# define SANITIZER_INTERFACE_ATTRIBUTE __declspec(dllexport)
36# endif
37# define SANITIZER_WEAK_ATTRIBUTE
4238# define SANITIZER_WEAK_IMPORT
4339#else
44# define SANITIZER_INTERFACE_ATTRIBUTE __attribute__((visibility("default")))
45# define SANITIZER_WEAK_ATTRIBUTE __attribute__((weak))
40# if SANITIZER_GO
41# define SANITIZER_INTERFACE_ATTRIBUTE
42# define SANITIZER_WEAK_ATTRIBUTE
43# elif SANITIZER_AMDGPU || SANITIZER_NVPTX
44# define SANITIZER_INTERFACE_ATTRIBUTE __attribute__((visibility("hidden")))
45# define SANITIZER_WEAK_ATTRIBUTE __attribute__((weak))
46# else
47# define SANITIZER_INTERFACE_ATTRIBUTE __attribute__((visibility("default")))
48# define SANITIZER_WEAK_ATTRIBUTE __attribute__((weak))
49# endif // SANITIZER_GO
4650# if SANITIZER_APPLE
4751# define SANITIZER_WEAK_IMPORT extern "C" __attribute((weak_import))
4852# else
lib/libtsan/sanitizer_common/sanitizer_linux.cpp+81-12
......@@ -90,10 +90,18 @@
9090extern "C" SANITIZER_WEAK_ATTRIBUTE const char *strerrorname_np(int);
9191# endif
9292
93# if SANITIZER_LINUX && defined(__loongarch__)
93# if SANITIZER_LINUX && \
94 (defined(__loongarch__) || defined(__hexagon__) || defined(__alpha__))
9495# include <sys/sysmacros.h>
9596# endif
9697
98// Hexagon uses statx() instead of stat64(). glibc provides struct statx
99// through <sys/stat.h>, but musl does not — pull it from <linux/stat.h>.
100// On this musl/hexagon combination the two headers coexist without conflict.
101# if SANITIZER_LINUX && defined(__hexagon__)
102# include <linux/stat.h>
103# endif
104
97105# if SANITIZER_LINUX && defined(__powerpc64__)
98106# include <asm/ptrace.h>
99107# endif
......@@ -254,6 +262,8 @@ ScopedBlockSignals::~ScopedBlockSignals() { SetSigProcMask(&saved_, nullptr); }
254262# include "sanitizer_syscall_linux_hexagon.inc"
255263# elif SANITIZER_LINUX && SANITIZER_LOONGARCH64
256264# include "sanitizer_syscall_linux_loongarch64.inc"
265# elif SANITIZER_LINUX && SANITIZER_ALPHA
266# include "sanitizer_syscall_linux_alpha.inc"
257267# else
258268# include "sanitizer_syscall_generic.inc"
259269# endif
......@@ -296,11 +306,13 @@ int internal_madvise(uptr addr, uptr length, int advice) {
296306 return internal_syscall(SYSCALL(madvise), addr, length, advice);
297307}
298308
299# if SANITIZER_FREEBSD
300309uptr internal_close_range(fd_t lowfd, fd_t highfd, int flags) {
310# if SANITIZER_FREEBSD || (SANITIZER_LINUX && defined(__NR_close_range))
301311 return internal_syscall(SYSCALL(close_range), lowfd, highfd, flags);
302}
303312# endif
313 return -1; // Not supported.
314}
315
304316uptr internal_close(fd_t fd) { return internal_syscall(SYSCALL(close), fd); }
305317
306318uptr internal_open(const char *filename, int flags) {
......@@ -341,7 +353,8 @@ uptr internal_ftruncate(fd_t fd, uptr size) {
341353 return res;
342354}
343355
344# if !SANITIZER_LINUX_USES_64BIT_SYSCALLS && SANITIZER_LINUX
356# if !SANITIZER_LINUX_USES_64BIT_SYSCALLS && SANITIZER_LINUX && \
357 !defined(__hexagon__)
345358static void stat64_to_stat(struct stat64 *in, struct stat *out) {
346359 internal_memset(out, 0, sizeof(*out));
347360 out->st_dev = in->st_dev;
......@@ -360,7 +373,8 @@ static void stat64_to_stat(struct stat64 *in, struct stat *out) {
360373}
361374# endif
362375
363# if SANITIZER_LINUX && defined(__loongarch__)
376# if SANITIZER_LINUX && \
377 (defined(__loongarch__) || defined(__hexagon__) || defined(__alpha__))
364378static void statx_to_stat(struct statx *in, struct stat *out) {
365379 internal_memset(out, 0, sizeof(*out));
366380 out->st_dev = makedev(in->stx_dev_major, in->stx_dev_minor);
......@@ -440,7 +454,7 @@ uptr internal_stat(const char *path, void *buf) {
440454# if SANITIZER_FREEBSD
441455 return internal_syscall(SYSCALL(fstatat), AT_FDCWD, (uptr)path, (uptr)buf, 0);
442456# elif SANITIZER_LINUX
443# if defined(__loongarch__)
457# if defined(__loongarch__) || defined(__hexagon__) || defined(__alpha__)
444458 struct statx bufx;
445459 int res = internal_syscall(SYSCALL(statx), AT_FDCWD, (uptr)path,
446460 AT_NO_AUTOMOUNT, STATX_BASIC_STATS, (uptr)&bufx);
......@@ -478,7 +492,7 @@ uptr internal_lstat(const char *path, void *buf) {
478492 return internal_syscall(SYSCALL(fstatat), AT_FDCWD, (uptr)path, (uptr)buf,
479493 AT_SYMLINK_NOFOLLOW);
480494# elif SANITIZER_LINUX
481# if defined(__loongarch__)
495# if defined(__loongarch__) || defined(__hexagon__) || defined(__alpha__)
482496 struct statx bufx;
483497 int res = internal_syscall(SYSCALL(statx), AT_FDCWD, (uptr)path,
484498 AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT,
......@@ -526,7 +540,7 @@ uptr internal_fstat(fd_t fd, void *buf) {
526540 int res = internal_syscall(SYSCALL(fstat64), fd, &kbuf);
527541 kernel_stat_to_stat(&kbuf, (struct stat *)buf);
528542 return res;
529# elif SANITIZER_LINUX && defined(__loongarch__)
543# elif SANITIZER_LINUX && (defined(__loongarch__) || defined(__alpha__))
530544 struct statx bufx;
531545 int res = internal_syscall(SYSCALL(statx), fd, "", AT_EMPTY_PATH,
532546 STATX_BASIC_STATS, (uptr)&bufx);
......@@ -535,6 +549,13 @@ uptr internal_fstat(fd_t fd, void *buf) {
535549# else
536550 return internal_syscall(SYSCALL(fstat), fd, (uptr)buf);
537551# endif
552# elif SANITIZER_LINUX && defined(__hexagon__)
553 // Hexagon musl lacks struct stat64; use statx() instead.
554 struct statx bufx;
555 int res = internal_syscall(SYSCALL(statx), fd, "", AT_EMPTY_PATH,
556 STATX_BASIC_STATS, (uptr)&bufx);
557 statx_to_stat(&bufx, (struct stat*)buf);
558 return res;
538559# else
539560 struct stat64 buf64;
540561 int res = internal_syscall(SYSCALL(fstat64), fd, &buf64);
......@@ -1003,7 +1024,7 @@ int internal_sigaction_norestorer(int signum, const void *act, void *oldact) {
10031024 // rt_sigaction, so we need to do the same (we'll need to reimplement the
10041025 // restorers; for x86_64 the restorer address can be obtained from
10051026 // oldact->sa_restorer upon a call to sigaction(xxx, NULL, oldact).
1006# if !SANITIZER_ANDROID || !SANITIZER_MIPS32
1027# if (!SANITIZER_ANDROID || !SANITIZER_MIPS32) && !defined(__alpha__)
10071028 k_act.sa_restorer = u_act->sa_restorer;
10081029# endif
10091030 }
......@@ -1019,7 +1040,7 @@ int internal_sigaction_norestorer(int signum, const void *act, void *oldact) {
10191040 internal_memcpy(&u_oldact->sa_mask, &k_oldact.sa_mask,
10201041 sizeof(__sanitizer_kernel_sigset_t));
10211042 u_oldact->sa_flags = k_oldact.sa_flags;
1022# if !SANITIZER_ANDROID || !SANITIZER_MIPS32
1043# if (!SANITIZER_ANDROID || !SANITIZER_MIPS32) && !defined(__alpha__)
10231044 u_oldact->sa_restorer = k_oldact.sa_restorer;
10241045# endif
10251046 }
......@@ -1228,6 +1249,16 @@ uptr GetMaxVirtualAddress() {
12281249 // loongarch64 also has multiple address space layouts: default is 47-bit.
12291250 // RISC-V 64 also has multiple address space layouts: 39, 48 and 57-bit.
12301251 return (1ULL << (MostSignificantSetBitIndex(GET_CURRENT_FRAME()) + 1)) - 1;
1252# elif SANITIZER_ALPHA
1253 // Linux/Alpha uses a 42-bit user VAS (TASK_SIZE = 0x40000000000). With
1254 // fixed shadow offset 0x10000000000 (1 TiB) the layout is:
1255 // LowMem: [0x000000000000, 0x00ffffffffff] (1 TiB)
1256 // LowShadow: [0x010000000000, 0x011fffffffff] (128 GiB)
1257 // ShadowGap: [0x012000000000, 0x012fffffffff]
1258 // HighShadow:[0x013000000000, 0x017fffffffff] (256 GiB)
1259 // HighMem: [0x018000000000, 0x03ffffffffff] (2.5 TiB, stack near top)
1260 // Capping at TASK_SIZE - 1 avoids treating kernel addresses as HighMem.
1261 return (1ULL << 42) - 1; // TASK_SIZE - 1
12311262# elif SANITIZER_MIPS64
12321263 return (1ULL << 40) - 1; // 0x000000ffffffffffUL;
12331264# elif defined(__s390x__)
......@@ -1894,6 +1925,39 @@ uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
18941925 : "memory");
18951926 return res;
18961927}
1928# elif defined(__hexagon__)
1929uptr internal_clone(int (*fn)(void*), void* child_stack, int flags, void* arg,
1930 int* parent_tidptr, void* newtls, int* child_tidptr) {
1931 if (!fn || !child_stack)
1932 return -EINVAL;
1933 child_stack = (char*)child_stack - 2 * sizeof(unsigned int);
1934 ((unsigned int*)child_stack)[0] = (uptr)fn;
1935 ((unsigned int*)child_stack)[1] = (uptr)arg;
1936
1937 // Hexagon clone syscall uses the generic argument order (no
1938 // CONFIG_CLONE_BACKWARDS): flags, stack, ptid, ctid, tls.
1939 register int r0 __asm__("r0") = flags;
1940 register void* r1 __asm__("r1") = child_stack;
1941 register int* r2 __asm__("r2") = parent_tidptr;
1942 register int* r3 __asm__("r3") = child_tidptr;
1943 register void* r4 __asm__("r4") = newtls;
1944 register int r6 __asm__("r6") = __NR_clone;
1945
1946 __asm__ __volatile__(
1947 "trap0(#1)\n" /* syscall */
1948 "{ p0 = cmp.eq(r0, #0)\n" /* child? */
1949 " if (!p0.new) jump:nt 1f }\n"
1950 "r1 = memw(r29 + #0)\n" /* r1 = fn */
1951 "r0 = memw(r29 + #4)\n" /* r0 = arg */
1952 "callr r1\n" /* fn(arg) */
1953 "r6 = #%7\n" /* __NR_exit */
1954 "trap0(#1)\n"
1955 "1:\n"
1956 : "=r"(r0)
1957 : "0"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r4), "r"(r6), "i"(__NR_exit)
1958 : "memory", "p0", "r1", "lr");
1959 return (uptr)r0;
1960}
18971961# endif
18981962# endif // SANITIZER_LINUX
18991963
......@@ -2427,7 +2491,7 @@ static void DumpSingleReg(ucontext_t *ctx, int RegNum) {
24272491# if SANITIZER_LINUX
24282492 ctx->uc_mcontext.gregs[RegNum]
24292493# elif SANITIZER_NETBSD
2430 ctx->uc_mcontext.__gregs[RegNum]
2494 (unsigned long long)ctx->uc_mcontext.__gregs[RegNum]
24312495# endif
24322496 );
24332497# elif defined(__i386__)
......@@ -2729,6 +2793,11 @@ static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
27292793 *pc = ucontext->uc_mcontext.__pc;
27302794 *bp = ucontext->uc_mcontext.__gregs[22];
27312795 *sp = ucontext->uc_mcontext.__gregs[3];
2796# elif defined(__alpha__)
2797 ucontext_t* ucontext = (ucontext_t*)context;
2798 *pc = ucontext->uc_mcontext.sc_pc;
2799 *bp = ucontext->uc_mcontext.sc_regs[15]; // $fp / $s6
2800 *sp = ucontext->uc_mcontext.sc_regs[30]; // $sp
27322801# else
27332802# error "Unsupported arch"
27342803# endif
......@@ -2819,7 +2888,7 @@ void CheckMPROTECT() {
28192888# endif
28202889}
28212890
2822void CheckNoDeepBind(const char *filename, int flag) {
2891void OnDlOpen(const char* filename, int flag) {
28232892# ifdef RTLD_DEEPBIND
28242893 if (flag & RTLD_DEEPBIND) {
28252894 Report(
lib/libtsan/sanitizer_common/sanitizer_linux.h+2-1
......@@ -86,7 +86,8 @@ int internal_sigaction_norestorer(int signum, const void *act, void *oldact);
8686void internal_sigdelset(__sanitizer_sigset_t *set, int signum);
8787# if defined(__x86_64__) || defined(__mips__) || defined(__aarch64__) || \
8888 defined(__powerpc64__) || defined(__s390__) || defined(__i386__) || \
89 defined(__arm__) || SANITIZER_RISCV64 || SANITIZER_LOONGARCH64
89 defined(__arm__) || defined(__hexagon__) || SANITIZER_RISCV64 || \
90 SANITIZER_LOONGARCH64
9091uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
9192 int *parent_tidptr, void *newtls, int *child_tidptr);
9293# endif
lib/libtsan/sanitizer_common/sanitizer_linux_libcdep.cpp+6-2
......@@ -284,6 +284,10 @@ static uptr ThreadDescriptorSizeFallback() {
284284# if defined(__powerpc64__)
285285 return 1776; // from glibc.ppc64le 2.20-8.fc21
286286# endif
287
288# if defined(__alpha__)
289 return 1824; // from glibc 2.43
290# endif
287291}
288292# endif // SANITIZER_GLIBC && !SANITIZER_GO
289293
......@@ -494,10 +498,10 @@ __attribute__((unused)) static void GetStaticTlsBoundary(uptr *addr, uptr *size,
494498 // loader places static TLS blocks this way not to waste space.
495499 uptr l = one;
496500 *align = ranges[l].align;
497 while (l != 0 && ranges[l].begin < ranges[l - 1].end + ranges[l].align)
501 while (l != 0 && ranges[l].begin <= ranges[l - 1].end + ranges[l].align)
498502 *align = Max(*align, ranges[--l].align);
499503 uptr r = one + 1;
500 while (r != len && ranges[r].begin < ranges[r - 1].end + ranges[r].align)
504 while (r != len && ranges[r].begin <= ranges[r - 1].end + ranges[r].align)
501505 *align = Max(*align, ranges[r++].align);
502506 *addr = ranges[l].begin;
503507 *size = ranges[r - 1].end - ranges[l].begin;
lib/libtsan/sanitizer_common/sanitizer_lzw.h+1-3
......@@ -26,9 +26,7 @@ ItOut LzwEncode(ItIn begin, ItIn end, ItOut out) {
2626
2727 // Sentinel value for substrings of len 1.
2828 static constexpr LzwCodeType kNoPrefix =
29 Min(DenseMapInfo<Substring>::getEmptyKey().first,
30 DenseMapInfo<Substring>::getTombstoneKey().first) -
31 1;
29 DenseMapInfo<Substring>::getEmptyKey().first - 1;
3230 DenseMap<Substring, LzwCodeType> prefix_to_code;
3331 {
3432 // Add all substring of len 1 as initial dictionary.
lib/libtsan/sanitizer_common/sanitizer_mac.cpp+30-2
......@@ -170,6 +170,10 @@ uptr internal_close(fd_t fd) {
170170 return close(fd);
171171}
172172
173uptr internal_close_range(fd_t lowfd, fd_t highfd, int flags) {
174 return -1; // Not supported.
175}
176
173177uptr internal_open(const char *filename, int flags) {
174178 return open(filename, flags);
175179}
......@@ -609,7 +613,13 @@ static uptr ApproximateOSVersionViaKernelVersion(VersStr vers) {
609613 u16 os_major = kernel_major - offset;
610614
611615 const char *format = "%d.0";
612 if (TARGET_OS_OSX) {
616 if (kernel_major >= 27) {
617 // with kernel major 27 <=> OSes 27.0, OS versions are aligned with kernel
618 os_major = kernel_major;
619 } else if (kernel_major >= 25) {
620 // with kernel_major 25 <=> OSes 26.0, OS versions are aligned
621 os_major = kernel_major + 1;
622 } else if (TARGET_OS_OSX) {
613623 if (os_major >= 16) { // macOS 11+
614624 os_major -= 5;
615625 } else { // macOS 10.15 and below
......@@ -666,6 +676,24 @@ static void MapToMacos(u16 *major, u16 *minor) {
666676 if (TARGET_OS_OSX)
667677 return;
668678
679 // All supported platforms (including DriverKit) have
680 // aligned version numbers in macOS 27+
681 if (*major >= 27)
682 return;
683
684# if TARGET_OS_DRIVERKIT
685 // Driverkit 25.0+ aligns with macOS 26+
686 if (*major >= 25) {
687 *major += 1;
688 return;
689 }
690# else
691 // macOS 26 and later have aligned version strings.
692 if (*major >= 26)
693 return;
694# endif
695
696 // Below are mappings for pre-macOS-25-aligned releases
669697 if (TARGET_OS_IOS || TARGET_OS_TV)
670698 *major += 2;
671699 else if (TARGET_OS_WATCH)
......@@ -1529,7 +1557,7 @@ void DumpProcessMap() {
15291557 Printf("End of module map.\n");
15301558}
15311559
1532void CheckNoDeepBind(const char *filename, int flag) {
1560void OnDlOpen(const char* filename, int flag) {
15331561 // Do nothing.
15341562}
15351563
lib/libtsan/sanitizer_common/sanitizer_netbsd.cpp+4
......@@ -126,6 +126,10 @@ uptr internal_close(fd_t fd) {
126126 return _sys_close(fd);
127127}
128128
129uptr internal_close_range(fd_t lowfd, fd_t highfd, int flags) {
130 return -1; // Not supported.
131}
132
129133uptr internal_open(const char *filename, int flags) {
130134 CHECK(&_sys_open);
131135 return _sys_open(filename, flags);
lib/libtsan/sanitizer_common/sanitizer_platform.h+33-2
......@@ -15,7 +15,8 @@
1515#if !defined(__linux__) && !defined(__FreeBSD__) && !defined(__NetBSD__) && \
1616 !defined(__APPLE__) && !defined(_WIN32) && !defined(__Fuchsia__) && \
1717 !(defined(__sun__) && defined(__svr4__)) && !defined(__HAIKU__) && \
18 !defined(__wasi__)
18 !defined(__wasi__) && !defined(__NVPTX__) && !defined(__AMDGPU__) && \
19 !defined(__SPIRV__) && !defined(_AIX)
1920# error "This operating system is not supported"
2021#endif
2122
......@@ -32,6 +33,12 @@
3233# define SANITIZER_LINUX 0
3334#endif
3435
36#if defined(_AIX)
37# define SANITIZER_AIX 1
38#else
39# define SANITIZER_AIX 0
40#endif
41
3542#if defined(__GLIBC__)
3643# define SANITIZER_GLIBC 1
3744#else
......@@ -151,7 +158,7 @@
151158
152159#define SANITIZER_POSIX \
153160 (SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_APPLE || \
154 SANITIZER_NETBSD || SANITIZER_SOLARIS || SANITIZER_HAIKU)
161 SANITIZER_NETBSD || SANITIZER_SOLARIS || SANITIZER_HAIKU || SANITIZER_AIX)
155162
156163#if __LP64__ || defined(_WIN64)
157164# define SANITIZER_WORDSIZE 64
......@@ -302,6 +309,30 @@
302309# define SANITIZER_LOONGARCH64 0
303310#endif
304311
312#if defined(__alpha__)
313# define SANITIZER_ALPHA 1
314#else
315# define SANITIZER_ALPHA 0
316#endif
317
318#if defined(__AMDGPU__)
319# define SANITIZER_AMDGPU 1
320#else
321# define SANITIZER_AMDGPU 0
322#endif
323
324#if defined(__NVPTX__)
325# define SANITIZER_NVPTX 1
326#else
327# define SANITIZER_NVPTX 0
328#endif
329
330#if defined(__SPIRV__)
331# define SANITIZER_SPIRV 1
332#else
333# define SANITIZER_SPIRV 0
334#endif
335
305336// By default we allow to use SizeClassAllocator64 on 64-bit platform.
306337// But in some cases SizeClassAllocator64 does not work well and we need to
307338// fallback to SizeClassAllocator32.
lib/libtsan/sanitizer_common/sanitizer_platform_interceptors.h+6-1
......@@ -201,6 +201,9 @@ SANITIZER_WEAK_IMPORT void *aligned_alloc(__sanitizer::usize __alignment,
201201
202202#define SANITIZER_INTERCEPT_READ SI_POSIX
203203#define SANITIZER_INTERCEPT_PREAD SI_POSIX
204#define SANITIZER_INTERCEPT___READ_CHK SI_GLIBC
205#define SANITIZER_INTERCEPT___PREAD_CHK SI_GLIBC
206#define SANITIZER_INTERCEPT___PREAD64_CHK SI_GLIBC
204207#define SANITIZER_INTERCEPT_WRITE SI_POSIX
205208#define SANITIZER_INTERCEPT_PWRITE SI_POSIX
206209
......@@ -393,6 +396,8 @@ SANITIZER_WEAK_IMPORT void *aligned_alloc(__sanitizer::usize __alignment,
393396#define SANITIZER_INTERCEPT_SHMCTL \
394397 (((SI_FREEBSD || SI_LINUX_NOT_ANDROID) && SANITIZER_WORDSIZE == 64) || \
395398 SI_NETBSD || SI_SOLARIS)
399// shmat calls REAL(shmctl), so it requires shmctl interception.
400#define SANITIZER_INTERCEPT_SHMAT SANITIZER_INTERCEPT_SHMCTL
396401#define SANITIZER_INTERCEPT_RANDOM_R SI_GLIBC
397402#define SANITIZER_INTERCEPT_PTHREAD_ATTR_GET SI_POSIX
398403#define SANITIZER_INTERCEPT_PTHREAD_ATTR_GETINHERITSCHED \
......@@ -545,7 +550,7 @@ SANITIZER_WEAK_IMPORT void *aligned_alloc(__sanitizer::usize __alignment,
545550#define SANITIZER_INTERCEPT___LIBC_MEMALIGN SI_GLIBC
546551#define SANITIZER_INTERCEPT_PVALLOC (SI_GLIBC || SI_ANDROID)
547552#define SANITIZER_INTERCEPT_CFREE (SI_GLIBC && !SANITIZER_RISCV64)
548#define SANITIZER_INTERCEPT_REALLOCARRAY SI_POSIX
553#define SANITIZER_INTERCEPT_REALLOCARRAY (SI_POSIX || SI_FUCHSIA)
549554#define SANITIZER_INTERCEPT_ALIGNED_ALLOC \
550555 (!SI_MAC || SI_MAC_SDK_10_15_AVAILABLE)
551556#define SANITIZER_INTERCEPT_MALLOC_USABLE_SIZE (!SI_MAC && !SI_NETBSD)
lib/libtsan/sanitizer_common/sanitizer_platform_limits_linux.cpp+1-1
......@@ -60,7 +60,7 @@ using namespace __sanitizer;
6060# if !defined(__powerpc64__) && !defined(__x86_64__) && \
6161 !defined(__aarch64__) && !defined(__mips__) && !defined(__s390__) && \
6262 !defined(__sparc__) && !defined(__riscv) && !defined(__hexagon__) && \
63 !defined(__loongarch__)
63 !defined(__loongarch__) && !defined(__alpha__)
6464COMPILER_CHECK(struct___old_kernel_stat_sz == sizeof(struct __old_kernel_stat));
6565#endif
6666
lib/libtsan/sanitizer_common/sanitizer_platform_limits_posix.cpp+57-25
......@@ -24,7 +24,7 @@
2424// Must go after undef _FILE_OFFSET_BITS.
2525#include "sanitizer_platform.h"
2626
27#if SANITIZER_LINUX || SANITIZER_APPLE || SANITIZER_HAIKU
27#if SANITIZER_LINUX || SANITIZER_APPLE || SANITIZER_HAIKU || SANITIZER_AIX
2828// Must go after undef _FILE_OFFSET_BITS.
2929#include "sanitizer_glibc_version.h"
3030
......@@ -61,11 +61,11 @@
6161#endif
6262
6363#if !SANITIZER_ANDROID
64#if !SANITIZER_HAIKU
65#include <sys/mount.h>
66#endif
67#include <sys/timeb.h>
68#include <utmpx.h>
64# if !SANITIZER_HAIKU && !SANITIZER_AIX
65# include <sys/mount.h>
66# endif
67# include <sys/timeb.h>
68# include <utmpx.h>
6969#endif
7070
7171#if SANITIZER_LINUX
......@@ -113,11 +113,15 @@ typedef struct user_fpregs elf_fpregset_t;
113113#endif
114114
115115#if !SANITIZER_ANDROID
116#include <ifaddrs.h>
117#if !SANITIZER_HAIKU
118#include <sys/ucontext.h>
119#include <wordexp.h>
120#endif
116# if !SANITIZER_AIX
117# include <ifaddrs.h>
118# else
119# include <netinet/in.h>
120# endif
121# if !SANITIZER_HAIKU
122# include <sys/ucontext.h>
123# include <wordexp.h>
124# endif
121125#endif
122126
123127#if SANITIZER_LINUX
......@@ -182,6 +186,17 @@ typedef struct user_fpregs elf_fpregset_t;
182186#include <sys/ioctl.h>
183187#endif
184188
189# if SANITIZER_AIX
190# include <netinet/ip_mroute.h>
191# include <stropts.h>
192# include <sys/ioctl.h>
193# include <sys/statfs.h>
194# include <unistd.h>
195# if HAVE_RPC_XDR_H
196# include <tirpc/rpc/xdr.h>
197# endif
198# endif
199
185200// Include these after system headers to avoid name clashes and ambiguities.
186201# include "sanitizer_common.h"
187202# include "sanitizer_internal_defs.h"
......@@ -293,7 +308,7 @@ namespace __sanitizer {
293308#define SIZEOF_STRUCT_USTAT 32
294309# elif defined(__arm__) || defined(__i386__) || defined(__mips__) || \
295310 defined(__powerpc__) || defined(__s390__) || defined(__sparc__) || \
296 defined(__hexagon__)
311 defined(__hexagon__) || defined(__alpha__)
297312# define SIZEOF_STRUCT_USTAT 20
298313# elif defined(__loongarch__)
299314 // Not used. The minimum Glibc version available for LoongArch is 2.36
......@@ -305,9 +320,12 @@ namespace __sanitizer {
305320 unsigned struct_ustat_sz = SIZEOF_STRUCT_USTAT;
306321 unsigned struct_rlimit64_sz = sizeof(struct rlimit64);
307322 unsigned struct_statvfs64_sz = sizeof(struct statvfs64);
308#endif // SANITIZER_GLIBC
323# elif SANITIZER_MUSL
324 // On musl, rlimit64 is an alias for rlimit.
325 unsigned struct_rlimit64_sz = sizeof(struct rlimit);
326# endif // SANITIZER_GLIBC
309327
310#if SANITIZER_LINUX && !SANITIZER_ANDROID
328# if SANITIZER_LINUX && !SANITIZER_ANDROID
311329 unsigned struct_timex_sz = sizeof(struct timex);
312330 unsigned struct_msqid_ds_sz = sizeof(struct msqid_ds);
313331 unsigned struct_mq_attr_sz = sizeof(struct mq_attr);
......@@ -556,13 +574,13 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
556574 const unsigned IOCTL_NOT_PRESENT = 0;
557575
558576 unsigned IOCTL_FIONBIO = FIONBIO;
559#if !SANITIZER_HAIKU
577# if !SANITIZER_HAIKU
560578 unsigned IOCTL_FIOASYNC = FIOASYNC;
561579 unsigned IOCTL_FIOCLEX = FIOCLEX;
562580 unsigned IOCTL_FIOGETOWN = FIOGETOWN;
563581 unsigned IOCTL_FIONCLEX = FIONCLEX;
564582 unsigned IOCTL_FIOSETOWN = FIOSETOWN;
565#endif
583# endif
566584 unsigned IOCTL_SIOCADDMULTI = SIOCADDMULTI;
567585 unsigned IOCTL_SIOCATMARK = SIOCATMARK;
568586 unsigned IOCTL_SIOCDELMULTI = SIOCDELMULTI;
......@@ -584,14 +602,14 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
584602 unsigned IOCTL_SIOCSIFNETMASK = SIOCSIFNETMASK;
585603 unsigned IOCTL_SIOCSPGRP = SIOCSPGRP;
586604
587#if !SANITIZER_HAIKU
605# if !SANITIZER_HAIKU
588606 unsigned IOCTL_TIOCCONS = TIOCCONS;
589607 unsigned IOCTL_TIOCGETD = TIOCGETD;
590608 unsigned IOCTL_TIOCNOTTY = TIOCNOTTY;
591609 unsigned IOCTL_TIOCPKT = TIOCPKT;
592610 unsigned IOCTL_TIOCSETD = TIOCSETD;
593611 unsigned IOCTL_TIOCSTI = TIOCSTI;
594#endif
612# endif
595613
596614 unsigned IOCTL_TIOCEXCL = TIOCEXCL;
597615 unsigned IOCTL_TIOCGPGRP = TIOCGPGRP;
......@@ -602,10 +620,12 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
602620 unsigned IOCTL_TIOCMSET = TIOCMSET;
603621 unsigned IOCTL_TIOCNXCL = TIOCNXCL;
604622 unsigned IOCTL_TIOCOUTQ = TIOCOUTQ;
623# if !SANITIZER_AIX
605624 unsigned IOCTL_TIOCSCTTY = TIOCSCTTY;
625# endif
606626 unsigned IOCTL_TIOCSPGRP = TIOCSPGRP;
607627 unsigned IOCTL_TIOCSWINSZ = TIOCSWINSZ;
608#if SANITIZER_LINUX && !SANITIZER_ANDROID
628# if SANITIZER_LINUX && !SANITIZER_ANDROID
609629 unsigned IOCTL_SIOCGETSGCNT = SIOCGETSGCNT;
610630 unsigned IOCTL_SIOCGETVIFCNT = SIOCGETVIFCNT;
611631#endif
......@@ -1067,6 +1087,9 @@ CHECK_SIZE_AND_OFFSET(addrinfo, ai_protocol);
10671087CHECK_SIZE_AND_OFFSET(addrinfo, ai_addrlen);
10681088CHECK_SIZE_AND_OFFSET(addrinfo, ai_canonname);
10691089CHECK_SIZE_AND_OFFSET(addrinfo, ai_addr);
1090# if SANITIZER_AIX
1091CHECK_SIZE_AND_OFFSET(addrinfo, ai_eflags);
1092# endif
10701093
10711094CHECK_TYPE_SIZE(hostent);
10721095CHECK_SIZE_AND_OFFSET(hostent, h_name);
......@@ -1113,11 +1136,13 @@ COMPILER_CHECK(sizeof(__sanitizer_dirent) <= sizeof(dirent));
11131136CHECK_SIZE_AND_OFFSET(dirent, d_ino);
11141137#if SANITIZER_APPLE
11151138CHECK_SIZE_AND_OFFSET(dirent, d_seekoff);
1116#elif SANITIZER_FREEBSD || SANITIZER_HAIKU
1139# elif SANITIZER_AIX
1140CHECK_SIZE_AND_OFFSET(dirent, d_offset);
1141# elif SANITIZER_FREEBSD || SANITIZER_HAIKU
11171142// There is no 'd_off' field on FreeBSD.
1118#else
1143# else
11191144CHECK_SIZE_AND_OFFSET(dirent, d_off);
1120#endif
1145# endif
11211146CHECK_SIZE_AND_OFFSET(dirent, d_reclen);
11221147
11231148#if SANITIZER_GLIBC
......@@ -1151,7 +1176,8 @@ CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_mask);
11511176// didn't exist.
11521177CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_flags);
11531178#endif
1154#if SANITIZER_LINUX && (!SANITIZER_ANDROID || !SANITIZER_MIPS32)
1179# if SANITIZER_LINUX && (!SANITIZER_ANDROID || !SANITIZER_MIPS32) && \
1180 !defined(__alpha__)
11551181CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_restorer);
11561182#endif
11571183
......@@ -1192,6 +1218,10 @@ CHECK_SIZE_AND_OFFSET(wordexp_t, we_wordc);
11921218CHECK_SIZE_AND_OFFSET(wordexp_t, we_wordv);
11931219CHECK_SIZE_AND_OFFSET(wordexp_t, we_offs);
11941220#endif
1221# if SANITIZER_AIX
1222CHECK_SIZE_AND_OFFSET(wordexp_t, we_sflags);
1223CHECK_SIZE_AND_OFFSET(wordexp_t, we_soffs);
1224# endif
11951225
11961226CHECK_TYPE_SIZE(tm);
11971227CHECK_SIZE_AND_OFFSET(tm, tm_sec);
......@@ -1203,10 +1233,12 @@ CHECK_SIZE_AND_OFFSET(tm, tm_year);
12031233CHECK_SIZE_AND_OFFSET(tm, tm_wday);
12041234CHECK_SIZE_AND_OFFSET(tm, tm_yday);
12051235CHECK_SIZE_AND_OFFSET(tm, tm_isdst);
1236# if !SANITIZER_AIX
12061237CHECK_SIZE_AND_OFFSET(tm, tm_gmtoff);
12071238CHECK_SIZE_AND_OFFSET(tm, tm_zone);
1239# endif
12081240
1209#if SANITIZER_LINUX
1241# if SANITIZER_LINUX
12101242CHECK_TYPE_SIZE(mntent);
12111243CHECK_SIZE_AND_OFFSET(mntent, mnt_fsname);
12121244CHECK_SIZE_AND_OFFSET(mntent, mnt_dir);
......@@ -1256,7 +1288,7 @@ CHECK_TYPE_SIZE(clock_t);
12561288CHECK_TYPE_SIZE(clockid_t);
12571289#endif
12581290
1259#if !SANITIZER_ANDROID && !SANITIZER_HAIKU
1291# if !SANITIZER_ANDROID && !SANITIZER_HAIKU && !SANITIZER_AIX
12601292CHECK_TYPE_SIZE(ifaddrs);
12611293CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_next);
12621294CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_name);
lib/libtsan/sanitizer_common/sanitizer_platform_limits_posix.h+69-13
......@@ -14,7 +14,7 @@
1414#ifndef SANITIZER_PLATFORM_LIMITS_POSIX_H
1515#define SANITIZER_PLATFORM_LIMITS_POSIX_H
1616
17#if SANITIZER_LINUX || SANITIZER_APPLE || SANITIZER_HAIKU
17#if SANITIZER_LINUX || SANITIZER_APPLE || SANITIZER_HAIKU || SANITIZER_AIX
1818
1919# include "sanitizer_internal_defs.h"
2020# include "sanitizer_mallinfo.h"
......@@ -29,7 +29,7 @@
2929# define SANITIZER_HAS_STAT64 0
3030# define SANITIZER_HAS_STATFS64 0
3131# endif
32# elif SANITIZER_GLIBC || SANITIZER_ANDROID
32# elif SANITIZER_GLIBC || SANITIZER_ANDROID || SANITIZER_AIX
3333# define SANITIZER_HAS_STAT64 1
3434# define SANITIZER_HAS_STATFS64 1
3535# elif SANITIZER_HAIKU
......@@ -103,9 +103,15 @@ const unsigned struct_kernel_stat64_sz = 104;
103103const unsigned struct_kernel_stat_sz = SANITIZER_ANDROID
104104 ? FIRST_32_SECOND_64(104, 128)
105105# if defined(_ABIN32) && _MIPS_SIM == _ABIN32
106# if defined(_TIME_BITS) && _TIME_BITS == 64
107 : FIRST_32_SECOND_64(112, 216);
108# else
106109 : FIRST_32_SECOND_64(176, 216);
110# endif
107111# elif SANITIZER_MUSL
108112 : FIRST_32_SECOND_64(160, 208);
113# elif defined(_TIME_BITS) && _TIME_BITS == 64
114 : FIRST_32_SECOND_64(112, 216);
109115# else
110116 : FIRST_32_SECOND_64(160, 216);
111117# endif
......@@ -133,6 +139,9 @@ const unsigned struct_kernel_stat64_sz = 0;
133139# elif defined(__loongarch__)
134140const unsigned struct_kernel_stat_sz = 128;
135141const unsigned struct_kernel_stat64_sz = 0;
142# elif defined(__alpha__)
143const unsigned struct_kernel_stat_sz = 80;
144const unsigned struct_kernel_stat64_sz = 136;
136145# endif
137146struct __sanitizer_perf_event_attr {
138147 unsigned type;
......@@ -323,7 +332,7 @@ struct __sanitizer_iovec {
323332 usize iov_len;
324333};
325334
326# if !SANITIZER_ANDROID
335# if !SANITIZER_ANDROID && !SANITIZER_AIX
327336struct __sanitizer_ifaddrs {
328337 struct __sanitizer_ifaddrs *ifa_next;
329338 char *ifa_name;
......@@ -337,7 +346,7 @@ struct __sanitizer_ifaddrs {
337346 void *ifa_dstaddr; // (struct sockaddr *)
338347 void *ifa_data;
339348};
340# endif // !SANITIZER_ANDROID
349# endif // !SANITIZER_ANDROID && !SANITIZER_AIX
341350
342351# if SANITIZER_APPLE
343352typedef unsigned long __sanitizer_pthread_key_t;
......@@ -345,7 +354,7 @@ typedef unsigned long __sanitizer_pthread_key_t;
345354typedef unsigned __sanitizer_pthread_key_t;
346355# endif
347356
348# if SANITIZER_LINUX && !SANITIZER_ANDROID
357# if (SANITIZER_LINUX && !SANITIZER_ANDROID) || SANITIZER_AIX
349358
350359struct __sanitizer_XDR {
351360 int x_op;
......@@ -440,12 +449,14 @@ struct __sanitizer_tm {
440449 int tm_wday;
441450 int tm_yday;
442451 int tm_isdst;
443# if SANITIZER_HAIKU
452# if !SANITIZER_AIX
453# if SANITIZER_HAIKU
444454 int tm_gmtoff;
445455# else
446456 long int tm_gmtoff;
447457# endif
448458 const char *tm_zone;
459# endif
449460};
450461
451462# if SANITIZER_LINUX
......@@ -513,11 +524,19 @@ struct __sanitizer_msghdr {
513524 struct __sanitizer_iovec *msg_iov;
514525 uptr msg_iovlen;
515526 void *msg_control;
527# if !SANITIZER_AIX
516528 uptr msg_controllen;
529# else
530 unsigned msg_controllen;
531# endif
517532 int msg_flags;
518533};
519534struct __sanitizer_cmsghdr {
535# if !SANITIZER_AIX
520536 uptr cmsg_len;
537# else
538 unsigned cmsg_len;
539# endif
521540 int cmsg_level;
522541 int cmsg_type;
523542};
......@@ -554,10 +573,23 @@ struct __sanitizer_dirent {
554573 unsigned short d_reclen;
555574 // more fields that we don't care about
556575};
576# elif defined(__alpha__)
577struct __sanitizer_dirent {
578 unsigned int d_ino; // ino_t is 32-bit on Alpha
579 int __pad; // explicit padding before d_off
580 unsigned long d_off;
581 unsigned short d_reclen;
582 // more fields that we don't care about
583};
557584# else
558585struct __sanitizer_dirent {
586# if SANITIZER_AIX
587 uptr d_offset;
588 uptr d_ino;
589# else
559590 uptr d_ino;
560591 uptr d_off;
592# endif
561593 unsigned short d_reclen;
562594 // more fields that we don't care about
563595};
......@@ -573,7 +605,7 @@ struct __sanitizer_dirent64 {
573605extern unsigned struct_sock_fprog_sz;
574606# endif
575607
576# if SANITIZER_HAIKU
608# if SANITIZER_HAIKU || SANITIZER_AIX
577609typedef int __sanitizer_clock_t;
578610# elif defined(__x86_64__) && !defined(_LP64)
579611typedef long long __sanitizer_clock_t;
......@@ -581,8 +613,10 @@ typedef long long __sanitizer_clock_t;
581613typedef long __sanitizer_clock_t;
582614# endif
583615
584# if SANITIZER_LINUX || SANITIZER_HAIKU
616# if SANITIZER_LINUX || SANITIZER_HAIKU || SANITIZER_AIX
585617typedef int __sanitizer_clockid_t;
618# endif
619# if SANITIZER_LINUX || SANITIZER_HAIKU
586620typedef unsigned long long __sanitizer_eventfd_t;
587621# endif
588622
......@@ -637,6 +671,14 @@ struct __sanitizer_sigset_t {
637671 // The size is determined by looking at sizeof of real sigset_t on linux.
638672 uptr val[128 / sizeof(uptr)];
639673};
674# elif SANITIZER_AIX
675struct __sanitizer_sigset_t {
676# if SANITIZER_WORDSIZE == 64
677 uptr val[4];
678# else
679 uptr val[2];
680# endif
681};
640682# endif
641683
642684struct __sanitizer_siginfo_pad {
......@@ -741,7 +783,7 @@ struct __sanitizer_sigaction {
741783# endif
742784# endif
743785# endif
744# if SANITIZER_LINUX || SANITIZER_HAIKU
786# if (SANITIZER_LINUX || SANITIZER_HAIKU) && !defined(__alpha__)
745787 void (*sa_restorer)();
746788# endif
747789# if defined(__mips__) && (SANITIZER_WORDSIZE == 32) && !SANITIZER_MUSL
......@@ -828,8 +870,12 @@ struct __sanitizer_addrinfo {
828870 int ai_family;
829871 int ai_socktype;
830872 int ai_protocol;
831# if SANITIZER_ANDROID || SANITIZER_APPLE || SANITIZER_HAIKU
873# if SANITIZER_ANDROID || SANITIZER_APPLE || SANITIZER_HAIKU || SANITIZER_AIX
874# if SANITIZER_AIX // AIX ai_addrlen type is size_t
875 uptr ai_addrlen;
876# else
832877 unsigned ai_addrlen;
878# endif
833879 char *ai_canonname;
834880 void *ai_addr;
835881# else // LINUX
......@@ -838,6 +884,9 @@ struct __sanitizer_addrinfo {
838884 char *ai_canonname;
839885# endif
840886 struct __sanitizer_addrinfo *ai_next;
887# if SANITIZER_AIX
888 int ai_eflags;
889# endif
841890};
842891
843892struct __sanitizer_hostent {
......@@ -854,7 +903,7 @@ struct __sanitizer_pollfd {
854903 short revents;
855904};
856905
857# if SANITIZER_ANDROID || SANITIZER_APPLE
906# if SANITIZER_ANDROID || SANITIZER_APPLE || SANITIZER_AIX
858907typedef unsigned __sanitizer_nfds_t;
859908# else
860909typedef unsigned long __sanitizer_nfds_t;
......@@ -892,6 +941,10 @@ struct __sanitizer_wordexp_t {
892941 uptr we_wordc;
893942 char **we_wordv;
894943 uptr we_offs;
944# if SANITIZER_AIX
945 int we_sflags;
946 uptr we_soffs;
947# endif
895948};
896949
897950# if SANITIZER_LINUX && !SANITIZER_ANDROID
......@@ -1023,7 +1076,7 @@ struct __sanitizer_cookie_io_functions_t {
10231076# define IOC_NRBITS 8
10241077# define IOC_TYPEBITS 8
10251078# if defined(__powerpc__) || defined(__powerpc64__) || defined(__mips__) || \
1026 defined(__sparc__)
1079 defined(__sparc__) || defined(__alpha__)
10271080# define IOC_SIZEBITS 13
10281081# define IOC_DIRBITS 3
10291082# define IOC_NONE 1U
......@@ -1193,7 +1246,9 @@ extern unsigned IOCTL_TIOCMGET;
11931246extern unsigned IOCTL_TIOCMSET;
11941247extern unsigned IOCTL_TIOCNXCL;
11951248extern unsigned IOCTL_TIOCOUTQ;
1249# if !SANITIZER_AIX
11961250extern unsigned IOCTL_TIOCSCTTY;
1251# endif
11971252extern unsigned IOCTL_TIOCSPGRP;
11981253extern unsigned IOCTL_TIOCSWINSZ;
11991254# if SANITIZER_LINUX && !SANITIZER_ANDROID
......@@ -1593,6 +1648,7 @@ extern const int si_SEGV_ACCERR;
15931648typedef void *__sanitizer_timer_t;
15941649# endif
15951650
1596#endif // SANITIZER_LINUX || SANITIZER_APPLE || SANITIZER_HAIKU
1651#endif // SANITIZER_LINUX || SANITIZER_APPLE || SANITIZER_HAIKU ||
1652 // SANITIZER_AIX
15971653
15981654#endif
lib/libtsan/sanitizer_common/sanitizer_platform_limits_solaris.cpp+1
......@@ -51,6 +51,7 @@
5151#include <sys/timeb.h>
5252#include <sys/times.h>
5353#include <sys/types.h>
54#include <sys/ucontext.h>
5455#include <sys/utsname.h>
5556#include <termios.h>
5657#include <time.h>
lib/libtsan/sanitizer_common/sanitizer_posix.cpp+9-7
......@@ -27,12 +27,13 @@
2727#include <signal.h>
2828#include <sys/mman.h>
2929
30#if SANITIZER_FREEBSD
30# if SANITIZER_FREEBSD || SANITIZER_AIX
3131// The MAP_NORESERVE define has been removed in FreeBSD 11.x, and even before
3232// that, it was never implemented. So just define it to zero.
33#undef MAP_NORESERVE
34#define MAP_NORESERVE 0
35#endif
33// Similarly, AIX does not define MAP_NORESERVE.
34# undef MAP_NORESERVE
35# define MAP_NORESERVE 0
36# endif
3637
3738namespace __sanitizer {
3839
......@@ -357,9 +358,10 @@ int GetNamedMappingFd(const char *name, uptr size, int *flags) {
357358 if (!common_flags()->decorate_proc_maps || !name)
358359 return -1;
359360 char shmname[200];
360 CHECK(internal_strlen(name) < sizeof(shmname) - 10);
361 internal_snprintf(shmname, sizeof(shmname), "/dev/shm/%zu [%s]",
362 internal_getpid(), name);
361 int len =
362 internal_snprintf(shmname, sizeof(shmname), "/dev/shm/%zu.%llu [%s]",
363 internal_getpid(), GetTid(), name);
364 CHECK_LT(len, sizeof(shmname));
363365 int o_cloexec = 0;
364366#if defined(O_CLOEXEC)
365367 o_cloexec = O_CLOEXEC;
lib/libtsan/sanitizer_common/sanitizer_posix.h+2-2
......@@ -28,9 +28,9 @@ namespace __sanitizer {
2828// Don't use directly, use __sanitizer::OpenFile() instead.
2929uptr internal_open(const char *filename, int flags);
3030uptr internal_open(const char *filename, int flags, u32 mode);
31# if SANITIZER_FREEBSD
31// Closes all file descriptors from lowfd to highfd (inclusive).
32// Returns 0 on success or non-zero if not supported on this platform.
3233uptr internal_close_range(fd_t lowfd, fd_t highfd, int flags);
33# endif
3434uptr internal_close(fd_t fd);
3535
3636uptr internal_read(fd_t fd, void *buf, uptr count);
lib/libtsan/sanitizer_common/sanitizer_posix_libcdep.cpp+12-9
......@@ -188,12 +188,13 @@ static uptr GetAltStackSize() {
188188 return SIGSTKSZ * 4;
189189}
190190
191void SetAlternateSignalStack() {
191void* SetAlternateSignalStack() {
192192 stack_t altstack, oldstack;
193193 CHECK_EQ(0, sigaltstack(nullptr, &oldstack));
194194 // If the alternate stack is already in place, do nothing.
195195 // Android always sets an alternate stack, but it's too small for us.
196 if (!SANITIZER_ANDROID && !(oldstack.ss_flags & SS_DISABLE)) return;
196 if (!SANITIZER_ANDROID && !(oldstack.ss_flags & SS_DISABLE))
197 return nullptr;
197198 // TODO(glider): the mapped stack should have the MAP_STACK flag in the
198199 // future. It is not required by man 2 sigaltstack now (they're using
199200 // malloc()).
......@@ -201,15 +202,18 @@ void SetAlternateSignalStack() {
201202 altstack.ss_sp = (char *)MmapOrDie(altstack.ss_size, __func__);
202203 altstack.ss_flags = 0;
203204 CHECK_EQ(0, sigaltstack(&altstack, nullptr));
205 return altstack.ss_sp;
204206}
205207
206void UnsetAlternateSignalStack() {
208void UnsetAlternateSignalStack(void* altstack_base) {
207209 stack_t altstack, oldstack;
208210 altstack.ss_sp = nullptr;
209211 altstack.ss_flags = SS_DISABLE;
210212 altstack.ss_size = GetAltStackSize(); // Some sane value required on Darwin.
211213 CHECK_EQ(0, sigaltstack(&altstack, &oldstack));
212 UnmapOrDie(oldstack.ss_sp, oldstack.ss_size);
214 if (altstack_base && altstack_base == oldstack.ss_sp) {
215 UnmapOrDie(oldstack.ss_sp, oldstack.ss_size);
216 }
213217}
214218
215219bool IsSignalHandlerFromSanitizer(int signum) {
......@@ -562,11 +566,10 @@ pid_t StartSubprocess(const char *program, const char *const argv[],
562566 internal_close(stderr_fd);
563567 }
564568
565# if SANITIZER_FREEBSD
566 internal_close_range(3, ~static_cast<fd_t>(0), 0);
567# else
568 for (int fd = sysconf(_SC_OPEN_MAX); fd > 2; fd--) internal_close(fd);
569# endif
569 // Close all fds except stdin/stdout/stderr before exec.
570 // Fallback to the loop if close_range is not supported.
571 if (internal_close_range(3, ~static_cast<fd_t>(0), 0) != 0)
572 for (int fd = sysconf(_SC_OPEN_MAX); fd > 2; fd--) internal_close(fd);
570573
571574 internal_execve(program, const_cast<char **>(&argv[0]),
572575 const_cast<char *const *>(envp));
lib/libtsan/sanitizer_common/sanitizer_redefine_builtins.h+17-5
......@@ -17,11 +17,23 @@
1717// The asm hack only works with GCC and Clang.
1818# if !defined(_WIN32) && !defined(_AIX) && !defined(__APPLE__)
1919
20asm(R"(
21 .set memcpy, __sanitizer_internal_memcpy
22 .set memmove, __sanitizer_internal_memmove
23 .set memset, __sanitizer_internal_memset
24 )");
20# if defined(__hexagon__)
21
22# define SANITIZER_REDEFINE_BUILTIN_ASM(name) \
23 asm(".set " #name ", __sanitizer_internal_" #name)
24
25# else
26
27# define SANITIZER_REDEFINE_BUILTIN_ASM(name) \
28 asm(#name " = __sanitizer_internal_" #name)
29
30# endif
31
32SANITIZER_REDEFINE_BUILTIN_ASM(memcpy);
33SANITIZER_REDEFINE_BUILTIN_ASM(memmove);
34SANITIZER_REDEFINE_BUILTIN_ASM(memset);
35
36# undef SANITIZER_REDEFINE_BUILTIN_ASM
2537
2638# if defined(__cplusplus) && \
2739 !defined(SANITIZER_COMMON_REDEFINE_BUILTINS_IN_STD)
lib/libtsan/sanitizer_common/sanitizer_solaris.cpp+4
......@@ -102,6 +102,10 @@ uptr internal_open(const char *filename, int flags, u32 mode) {
102102 return _REAL64(open)(filename, flags, mode);
103103}
104104
105uptr internal_close_range(fd_t lowfd, fd_t highfd, int flags) {
106 return -1; // Not supported.
107}
108
105109DECLARE__REAL_AND_INTERNAL(uptr, read, fd_t fd, void *buf, uptr count) {
106110 return _REAL(read)(fd, buf, count);
107111}
lib/libtsan/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp+11-3
......@@ -16,7 +16,8 @@
1616#if SANITIZER_LINUX && \
1717 (defined(__x86_64__) || defined(__mips__) || defined(__aarch64__) || \
1818 defined(__powerpc64__) || defined(__s390__) || defined(__i386__) || \
19 defined(__arm__) || SANITIZER_RISCV64 || SANITIZER_LOONGARCH64)
19 defined(__arm__) || defined(__hexagon__) || SANITIZER_RISCV64 || \
20 SANITIZER_LOONGARCH64)
2021
2122#include "sanitizer_stoptheworld.h"
2223
......@@ -32,8 +33,8 @@
3233#include <sys/uio.h> // for iovec
3334#include <elf.h> // for NT_PRSTATUS
3435#if (defined(__aarch64__) || defined(__powerpc64__) || \
35 SANITIZER_RISCV64 || SANITIZER_LOONGARCH64) && \
36 !SANITIZER_ANDROID
36 defined(__hexagon__) || SANITIZER_RISCV64 || \
37 SANITIZER_LOONGARCH64) && !SANITIZER_ANDROID
3738// GLIBC 2.20+ sys/user does not include asm/ptrace.h
3839# include <asm/ptrace.h>
3940#endif
......@@ -613,6 +614,13 @@ typedef _user_regs_struct regs_struct;
613614static constexpr uptr kExtraRegs[] = {0};
614615#define ARCH_IOVEC_FOR_GETREGSET
615616
617#elif defined(__hexagon__)
618#include <asm/user.h>
619typedef struct user_regs_struct regs_struct;
620#define REG_SP r29
621static constexpr uptr kExtraRegs[] = {0};
622#define ARCH_IOVEC_FOR_GETREGSET
623
616624#else
617625#error "Unsupported architecture"
618626#endif // SANITIZER_ANDROID && defined(__arm__)
lib/libtsan/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp+7-7
......@@ -475,6 +475,13 @@ static SymbolizerTool *ChooseExternalSymbolizer(LowLevelAllocator *allocator) {
475475 return new (*allocator) Addr2LinePool(found_path, allocator);
476476 }
477477 }
478
479# if SANITIZER_APPLE
480 Report(
481 "WARN: No external symbolizers found. Symbols may be missing or "
482 "unreliable.\n");
483 Report("HINT: Is PATH set? Does sandbox allow file-read of /usr/bin/atos?\n");
484# endif
478485 return nullptr;
479486# endif // SANITIZER_DISABLE_SYMBOLIZER_PATH_SEARCH
480487}
......@@ -509,13 +516,6 @@ static void ChooseSymbolizerTools(IntrusiveList<SymbolizerTool> *list,
509516 }
510517
511518# if SANITIZER_APPLE
512 if (list->empty()) {
513 Report(
514 "WARN: No external symbolizers found. Symbols may be missing or "
515 "unreliable.\n");
516 Report(
517 "HINT: Is PATH set? Does sandbox allow file-read of /usr/bin/atos?\n");
518 }
519519 VReport(2, "Using dladdr symbolizer.\n");
520520 list->push_back(new (*allocator) DlAddrSymbolizer());
521521# endif // SANITIZER_APPLE
lib/libtsan/sanitizer_common/sanitizer_symbolizer_report.cpp+7-6
......@@ -184,7 +184,7 @@ static void MaybeReportNonExecRegion(uptr pc) {
184184 MemoryMappedSegment segment;
185185 while (proc_maps.Next(&segment)) {
186186 if (pc >= segment.start && pc < segment.end && !segment.IsExecutable())
187 Report("Hint: PC is at a non-executable region. Maybe a wild jump?\n");
187 Report("HINT: PC is at a non-executable region. Maybe a wild jump?\n");
188188 }
189189#endif
190190}
......@@ -254,7 +254,7 @@ static void ReportDeadlySignalImpl(const SignalContext &sig, u32 tid,
254254 (void *)sig.bp, (void *)sig.sp, tid);
255255 Printf("%s", d.Default());
256256 if (sig.pc < GetPageSizeCached())
257 Report("Hint: pc points to the zero page.\n");
257 Report("HINT: pc points to the zero page.\n");
258258 if (sig.is_memory_access) {
259259 const char *access_type =
260260 sig.write_flag == SignalContext::Write
......@@ -262,11 +262,12 @@ static void ReportDeadlySignalImpl(const SignalContext &sig, u32 tid,
262262 : (sig.write_flag == SignalContext::Read ? "READ" : "UNKNOWN");
263263 Report("The signal is caused by a %s memory access.\n", access_type);
264264 if (!sig.is_true_faulting_addr)
265 Report("Hint: this fault was caused by a dereference of a high value "
266 "address (see register values below). Disassemble the provided "
267 "pc to learn which register was used.\n");
265 Report(
266 "HINT: this fault was caused by a dereference of a high value "
267 "address (see register values below). Disassemble the provided "
268 "pc to learn which register was used.\n");
268269 else if (sig.addr < GetPageSizeCached())
269 Report("Hint: address points to the zero page.\n");
270 Report("HINT: address points to the zero page.\n");
270271 }
271272 MaybeReportNonExecRegion(sig.pc);
272273 InternalMmapVector<BufferedStackTrace> stack_buffer(1);
lib/libtsan/sanitizer_common/sanitizer_unwind_win.cpp+43-6
......@@ -43,10 +43,47 @@ void BufferedStackTrace::UnwindSlow(uptr pc, u32 max_depth) {
4343 trace_buffer[0] = pc;
4444}
4545
46#ifdef __clang__
47#pragma clang diagnostic push
48#pragma clang diagnostic ignored "-Wframe-larger-than="
49#endif
46PVOID CALLBACK FallbackFunctionTableAccess(HANDLE hProcess,
47 DWORD64 dwAddrBase) {
48 // First try DbgHelp's function.
49 if (PVOID pResult =
50 __sanitizer::SymFunctionTableAccess64(hProcess, dwAddrBase)) {
51 return pResult;
52 }
53
54 // Fall back to RtlLookupFunctionEntry for dynamic code.
55 // Function registered with RtlAddFunctionTable is not necessarily registered
56 // with DbgHelp, so this is required to cover some edge cases (e.g. JIT
57 // compilers can use Rtl* functions).
58# if SANITIZER_WINDOWS64
59 DWORD64 dw64ImageBase = 0;
60 return RtlLookupFunctionEntry(dwAddrBase, &dw64ImageBase, nullptr);
61# else
62 return nullptr;
63# endif
64}
65
66DWORD64 CALLBACK FallbackGetModuleBase(HANDLE hProcess, DWORD64 dwAddr) {
67 if (DWORD64 dwResult = __sanitizer::SymGetModuleBase64(hProcess, dwAddr)) {
68 return dwResult;
69 }
70
71 // Both GetModuleBase and FunctionTableAccess must provide this fallback,
72 // otherwise dynamic functions won't be properly unwound.
73# if SANITIZER_WINDOWS64
74 DWORD64 dw64ImageBase = 0;
75 if (RtlLookupFunctionEntry(dwAddr, &dw64ImageBase, nullptr)) {
76 return dw64ImageBase;
77 }
78# endif
79
80 return 0;
81}
82
83# ifdef __clang__
84# pragma clang diagnostic push
85# pragma clang diagnostic ignored "-Wframe-larger-than="
86# endif
5087void BufferedStackTrace::UnwindSlow(uptr pc, void *context, u32 max_depth) {
5188 CHECK(context);
5289 CHECK_GE(max_depth, 2);
......@@ -91,8 +128,8 @@ void BufferedStackTrace::UnwindSlow(uptr pc, void *context, u32 max_depth) {
91128 stack_frame.AddrFrame.Mode = AddrModeFlat;
92129 stack_frame.AddrStack.Mode = AddrModeFlat;
93130 while (StackWalk64(machine_type, GetCurrentProcess(), GetCurrentThread(),
94 &stack_frame, &ctx, NULL, SymFunctionTableAccess64,
95 SymGetModuleBase64, NULL) &&
131 &stack_frame, &ctx, NULL, FallbackFunctionTableAccess,
132 FallbackGetModuleBase, NULL) &&
96133 size < Min(max_depth, kStackTraceMax)) {
97134 trace_buffer[size++] = (uptr)stack_frame.AddrPC.Offset;
98135 }
lib/libtsan/sanitizer_common/sanitizer_win.cpp+4-3
......@@ -913,11 +913,12 @@ void ReportFile::Write(const char *buffer, uptr length) {
913913 }
914914}
915915
916void SetAlternateSignalStack() {
916void* SetAlternateSignalStack() {
917917 // FIXME: Decide what to do on Windows.
918 return nullptr;
918919}
919920
920void UnsetAlternateSignalStack() {
921void UnsetAlternateSignalStack(void* altstack_base) {
921922 // FIXME: Decide what to do on Windows.
922923}
923924
......@@ -1222,7 +1223,7 @@ int WaitForProcess(pid_t pid) { return -1; }
12221223// FIXME implement on this platform.
12231224void GetMemoryProfile(fill_profile_f cb, uptr *stats) {}
12241225
1225void CheckNoDeepBind(const char *filename, int flag) {
1226void OnDlOpen(const char* filename, int flag) {
12261227 // Do nothing.
12271228}
12281229
lib/libtsan/tsan_adaptive_delay.cpp created+433
......@@ -0,0 +1,433 @@
1//===-- tsan_adaptive_delay.h -----------------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file is a part of ThreadSanitizer (TSan), a race detector.
10//
11//===----------------------------------------------------------------------===//
12
13#include "tsan_adaptive_delay.h"
14
15#include "interception/interception.h"
16#include "sanitizer_common/sanitizer_allocator_internal.h"
17#include "sanitizer_common/sanitizer_common.h"
18#include "sanitizer_common/sanitizer_errno_codes.h"
19#include "tsan_interface.h"
20#include "tsan_rtl.h"
21
22namespace __tsan {
23
24namespace {
25
26// =============================================================================
27// DelaySpec: Represents a delay configuration parsed from flag strings
28// =============================================================================
29//
30// Delay can be specified as:
31// - "spin=N" : Spin for up to N cycles (very short delays)
32// - "yield" : Call sched_yield() once
33// - "sleep_us=N" : Sleep for up to N microseconds
34
35enum class DelayType { Spin, Yield, SleepUs };
36
37struct DelaySpec {
38 DelayType type;
39 int value; // spin cycles or sleep_us value; ignored for yield
40
41 // Both estimates below are used internally as a very rough estimate for
42 // delay overhead calculation, to cap the overall delay to the
43 // adaptive_delay_aggressiveness option. They're not intended to be 100%
44 // accurate on any or all architectures/operating systems, or for use in any
45 // other contexts.
46 //
47 // Estimated nanoseconds per spin cycle (volatile loop iteration).
48 static constexpr u64 kNsPerSpinCycle = 1;
49 // Estimated nanoseconds for a yield (context switch overhead)
50 static constexpr u64 kNsPerYield = 500;
51
52 static DelaySpec Parse(const char* str) {
53 DelaySpec spec;
54 if (internal_strncmp(str, "spin=", 5) == 0) {
55 spec.type = DelayType::Spin;
56 spec.value = internal_atoll(str + 5);
57 if (spec.value <= 0 || spec.value > 10000) {
58 Printf(
59 "FATAL: Invalid TSAN_OPTIONS spin value '%s'; value must be "
60 "between 1 and 10000\n",
61 str);
62 Die();
63 }
64 } else if (internal_strcmp(str, "yield") == 0) {
65 spec.type = DelayType::Yield;
66 spec.value = 0;
67 } else if (internal_strncmp(str, "sleep_us=", 9) == 0) {
68 spec.type = DelayType::SleepUs;
69 spec.value = internal_atoll(str + 9);
70 if (spec.value <= 0) {
71 Printf(
72 "FATAL: Invalid TSAN_OPTIONS sleep_us value '%s'; value must be a "
73 "positive integer\n",
74 str);
75 Die();
76 }
77 } else {
78 Printf("FATAL: Unrecognized delay spec '%s', check TSAN_OPTIONS\n", str);
79 Die();
80 }
81 return spec;
82 }
83
84 const char* TypeName() const {
85 switch (type) {
86 case DelayType::Spin:
87 return "spin";
88 case DelayType::Yield:
89 return "yield";
90 case DelayType::SleepUs:
91 return "sleep_us";
92 }
93 return "unknown";
94 }
95};
96
97} // namespace
98
99// =============================================================================
100// AdaptiveDelayImpl: Time-budget aware delay injection for race exposure
101// =============================================================================
102//
103// This implementation injects delays to expose data races while maintaining a
104// configurable overhead target. It uses several strategies:
105//
106// 1. Time-Budget Controller: Tracks cumulative delays vs wall-clock time
107// and adjusts delay probability to maintain target overhead.
108//
109// 2. Tiered Delays: Different delay strategies for different op types:
110// - Relaxed atomics: Very rare sampling, tiny spin delays
111// - Sync atomics (acq/rel/seq_cst): Moderate sampling, small usleep
112// - Mutex/CV ops: Higher sampling, larger delays
113// - Thread create/join: Always delay (rare but high value)
114//
115// 3. Address-based Sampling: Exponential backoff per address to avoid
116// repeatedly delaying hot atomics.
117
118struct AdaptiveDelayImpl {
119 ALWAYS_INLINE static AdaptiveDelayState* TLS() {
120 return &cur_thread()->adaptive_delay_state;
121 }
122 ALWAYS_INLINE static unsigned int* GetRandomSeed() {
123 return &TLS()->tls_random_seed_;
124 }
125 ALWAYS_INLINE static void SetRandomSeed(unsigned int seed) {
126 TLS()->tls_random_seed_ = seed;
127 }
128
129 // The public facing option is adaptive_delay_aggressiveness, which is an
130 // opaque value for the user to tune the amount of delay injected into the
131 // program. Internally, the implementation maps the aggressiveness to a target
132 // percent delay for the overall program runtime. It's not easy to implement
133 // a true wall clock delay target (e.g., 25% program wall time slowdown)
134 // because 1) spin loops and yield are hard to calculate actual wall time
135 // slowness and 2) usleep(N) is often slower than advertised. Thus, we keep
136 // the user facing parameter opaque to not under deliver on a promise of
137 // percent wall time slowdown.
138 struct TimeBudget {
139 int target_overhead_pct_;
140 Percent target_low_;
141 Percent target_high_;
142
143 void Init(int target_pct) {
144 target_overhead_pct_ = target_pct;
145 target_low_ = Percent::FromPct(
146 target_overhead_pct_ >= 5 ? target_overhead_pct_ - 5 : 0);
147 target_high_ = Percent::FromPct(target_overhead_pct_ + 5);
148 }
149
150 static constexpr u64 BucketDurationNs = 30'000'000'000ULL;
151
152 void RecordDelay(u64 delay_ns) {
153 u64 now = NanoTime();
154 u64 elapsed_ns = now - TLS()->bucket_start_ns_;
155
156 if (elapsed_ns >= BucketDurationNs) {
157 // Shift: old bucket is discarded, new becomes old, start fresh new
158 TLS()->delay_buckets_ns_[0] = TLS()->delay_buckets_ns_[1];
159 TLS()->delay_buckets_ns_[1] = 0;
160 TLS()->bucket_start_ns_ = now;
161 TLS()->bucket0_window_ns = BucketDurationNs;
162 }
163
164 TLS()->delay_buckets_ns_[1] += delay_ns;
165 }
166
167 Percent GetOverheadPercent() {
168 u64 now = NanoTime();
169 u64 elapsed_ns = now - TLS()->bucket_start_ns_;
170
171 // Need at least 1ms to calculate
172 if (elapsed_ns < 1'000'000ULL)
173 return Percent::FromPct(0);
174
175 if (elapsed_ns > BucketDurationNs * 2) {
176 // Both buckets are stale
177 return Percent::FromPct(0);
178 } else if (elapsed_ns > BucketDurationNs) {
179 // bucket[0] is stale, use only bucket[1] (current bucket)
180 u64 total_delay_ns = TLS()->delay_buckets_ns_[1];
181 return Percent::FromRatio(total_delay_ns, elapsed_ns);
182 } else {
183 u64 total_delay_ns =
184 TLS()->delay_buckets_ns_[0] + TLS()->delay_buckets_ns_[1];
185 u64 window_ns = TLS()->bucket0_window_ns + elapsed_ns;
186 return Percent::FromRatio(total_delay_ns, window_ns);
187 }
188 }
189
190 bool ShouldDelay() {
191 Percent ratio = GetOverheadPercent();
192
193 if (ratio < target_low_)
194 return true;
195 if (ratio > target_high_)
196 return false;
197
198 // Linear interpolation: at target_low -> 100%, at target_high -> 0%
199 Percent prob = (target_high_ - ratio) / (target_high_ - target_low_);
200 return prob.RandomCheck(GetRandomSeed());
201 }
202 };
203
204 // Address Sampler with Exponential Backoff
205 struct AddressSampler {
206 static constexpr u64 TABLE_SIZE = 2048;
207 struct Entry {
208 atomic_uintptr_t addr_;
209 atomic_uint32_t count_;
210 };
211 Entry table_[TABLE_SIZE];
212 static constexpr u32 ExponentialBackoffCap = 64;
213
214 void Init() {
215 for (u64 i = 0; i < TABLE_SIZE; ++i) {
216 atomic_store(&table_[i].addr_, 0, memory_order_relaxed);
217 atomic_store(&table_[i].count_, 0, memory_order_relaxed);
218 }
219 }
220
221 static ALWAYS_INLINE u64 splitmix64(u64 x) {
222 x = (x ^ (x >> 30)) * 0xBF58476D1CE4E5B9ULL;
223 x = (x ^ (x >> 27)) * 0x94D049BB133111EBULL;
224 x = x ^ (x >> 31);
225 return x;
226 }
227
228 // Uses exponential backoff: delay on 1st, 2nd, 4th, 8th, 16th, ...
229 bool ShouldDelayAddr(uptr addr) {
230 u64 idx = splitmix64(addr >> 3) & (TABLE_SIZE - 1);
231 Entry& e = table_[idx];
232
233 // This function is not thread safe.
234 // If two threads access the same hashed entry in parallel,
235 // worst case, we may end up returning true too often. This is
236 // acceptable...instead of full locking.
237
238 uptr stored_addr = atomic_load(&e.addr_, memory_order_relaxed);
239 if (stored_addr != addr) {
240 // Hash Collision - reset
241 atomic_store(&e.addr_, addr, memory_order_relaxed);
242 atomic_store(&e.count_, 1, memory_order_relaxed);
243 return true;
244 }
245
246 u32 count = atomic_fetch_add(&e.count_, 1, memory_order_relaxed) + 1;
247
248 if ((count & (count - 1)) == 0 && count <= ExponentialBackoffCap)
249 return true;
250 return false;
251 }
252 };
253
254 TimeBudget budget_;
255 AddressSampler sampler_;
256
257 int relaxed_sample_rate_;
258 int sync_atomic_sample_rate_;
259 int mutex_sample_rate_;
260 DelaySpec atomic_delay_;
261 DelaySpec sync_delay_;
262
263 void Init() { InitTls(); }
264
265 void InitTls() {
266 TLS()->bucket_start_ns_ = NanoTime();
267 TLS()->delay_buckets_ns_[0] = 0;
268 TLS()->delay_buckets_ns_[1] = 0;
269 TLS()->bucket0_window_ns = 0;
270
271 SetRandomSeed(NanoTime());
272 TLS()->tls_initialized_ = true;
273 }
274
275 bool IsTlsInitialized() const { return TLS()->tls_initialized_; }
276
277 AdaptiveDelayImpl() {
278 relaxed_sample_rate_ = flags()->adaptive_delay_relaxed_sample_rate;
279 sync_atomic_sample_rate_ = flags()->adaptive_delay_sync_atomic_sample_rate;
280 mutex_sample_rate_ = flags()->adaptive_delay_mutex_sample_rate;
281 atomic_delay_ = DelaySpec::Parse(flags()->adaptive_delay_max_atomic);
282 sync_delay_ = DelaySpec::Parse(flags()->adaptive_delay_max_sync);
283
284 int delay_aggressiveness = flags()->adaptive_delay_aggressiveness;
285 if (delay_aggressiveness < 1)
286 delay_aggressiveness = 1;
287
288 budget_.Init(delay_aggressiveness);
289 sampler_.Init();
290
291 VPrintf(1, "INFO: ThreadSanitizer AdaptiveDelay initialized\n");
292 VPrintf(1, " Delay aggressiveness: %d\n", delay_aggressiveness);
293 VPrintf(1, " Relaxed atomic sample rate: 1/%d\n", relaxed_sample_rate_);
294 VPrintf(1, " Sync atomic sample rate: 1/%d\n", sync_atomic_sample_rate_);
295 VPrintf(1, " Mutex sample rate: 1/%d\n", mutex_sample_rate_);
296 VPrintf(1, " Atomic delay: %s=%d\n", atomic_delay_.TypeName(),
297 atomic_delay_.value);
298 VPrintf(1, " Sync delay: %s=%d\n", sync_delay_.TypeName(),
299 sync_delay_.value);
300 }
301
302 void DoSpinDelay(int iters) {
303 volatile int v = 0;
304 for (int i = 0; i < iters; ++i) v = i;
305 (void)v;
306 budget_.RecordDelay(iters * DelaySpec::kNsPerSpinCycle);
307 }
308
309 void DoYieldDelay() {
310 internal_sched_yield();
311 budget_.RecordDelay(DelaySpec::kNsPerYield);
312 }
313
314 void DoSleepUsDelay(int max_us) {
315 // Use two Rand() calls to get full 32-bit range for larger sleep values
316 u32 rnd = ((u32)Rand(GetRandomSeed()) << 16) | Rand(GetRandomSeed());
317 int delay_us = 1 + (rnd % max_us);
318 internal_usleep(delay_us);
319 budget_.RecordDelay(delay_us * 1000ULL);
320 }
321
322 void ExecuteDelay(const DelaySpec& spec) {
323 switch (spec.type) {
324 case DelayType::Spin: {
325 int iters = 1 + (Rand(GetRandomSeed()) % spec.value);
326 DoSpinDelay(iters);
327 break;
328 }
329 case DelayType::Yield:
330 DoYieldDelay();
331 break;
332 case DelayType::SleepUs:
333 DoSleepUsDelay(spec.value);
334 break;
335 }
336 }
337
338 void AtomicRelaxedOpDelay() {
339 if ((Rand(GetRandomSeed()) % relaxed_sample_rate_) != 0)
340 return;
341 if (!budget_.ShouldDelay())
342 return;
343
344 int iters = 10 + (Rand(GetRandomSeed()) % 10);
345 DoSpinDelay(iters);
346 }
347
348 void AtomicSyncOpDelay(uptr* addr) {
349 if ((Rand(GetRandomSeed()) % sync_atomic_sample_rate_) != 0)
350 return;
351 if (!budget_.ShouldDelay())
352 return;
353
354 if (addr && !sampler_.ShouldDelayAddr(*addr))
355 return;
356
357 ExecuteDelay(atomic_delay_);
358 }
359
360 void AtomicOpFence(int mo) {
361 CHECK(IsTlsInitialized());
362
363 if (mo < mo_acquire)
364 AtomicRelaxedOpDelay();
365 else
366 AtomicSyncOpDelay(nullptr);
367 }
368
369 void AtomicOpAddr(uptr addr, int mo) {
370 CHECK(IsTlsInitialized());
371
372 if (mo < mo_acquire)
373 AtomicRelaxedOpDelay();
374 else
375 AtomicSyncOpDelay(&addr);
376 }
377
378 void UnsampledDelay() {
379 CHECK(IsTlsInitialized());
380
381 if (!budget_.ShouldDelay())
382 return;
383
384 ExecuteDelay(sync_delay_);
385 }
386
387 void SyncOp() {
388 CHECK(IsTlsInitialized());
389
390 if ((Rand(GetRandomSeed()) % mutex_sample_rate_) != 0)
391 return;
392 if (!budget_.ShouldDelay())
393 return;
394
395 ExecuteDelay(sync_delay_);
396 }
397
398 void BeforeChildThreadRuns() {
399 InitTls();
400 UnsampledDelay();
401 }
402
403 void AfterThreadCreation() { UnsampledDelay(); }
404};
405
406AdaptiveDelayImpl& GetImpl() {
407 static AdaptiveDelayImpl impl;
408 return impl;
409}
410
411bool AdaptiveDelay::is_adaptive_delay_enabled;
412
413void AdaptiveDelay::InitImpl() {
414 AdaptiveDelay::is_adaptive_delay_enabled = flags()->enable_adaptive_delay;
415 if (!AdaptiveDelay::is_adaptive_delay_enabled)
416 return;
417
418 GetImpl().Init();
419}
420
421void AdaptiveDelay::SyncOpImpl() { GetImpl().SyncOp(); }
422void AdaptiveDelay::AtomicOpFenceImpl(int mo) { GetImpl().AtomicOpFence(mo); }
423void AdaptiveDelay::AtomicOpAddrImpl(__sanitizer::uptr addr, int mo) {
424 GetImpl().AtomicOpAddr(addr, mo);
425}
426void AdaptiveDelay::AfterThreadCreationImpl() {
427 GetImpl().AfterThreadCreation();
428}
429void AdaptiveDelay::BeforeChildThreadRunsImpl() {
430 GetImpl().BeforeChildThreadRuns();
431}
432
433} // namespace __tsan
lib/libtsan/tsan_adaptive_delay.h created+173
......@@ -0,0 +1,173 @@
1//===-- tsan_adaptive_delay.h -----------------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file is a part of ThreadSanitizer (TSan), a race detector.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef TSAN_ADAPTIVE_DELAY_H
14#define TSAN_ADAPTIVE_DELAY_H
15
16#include "sanitizer_common/sanitizer_common.h"
17#include "sanitizer_common/sanitizer_internal_defs.h"
18
19namespace __tsan {
20
21// AdaptiveDelay injects delays at synchronization points, atomic operations,
22// and thread lifecycle events to increase the likelihood of exposing data
23// races. The delay injection is controlled by an approximate time budget to
24// maintain a configurable overhead target.
25//
26// SyncOp() delays non-atomic synchronization points (those with clear
27// happens-before relationships):
28// - Acquire operations like locking a mutex delays before the mutex is locked.
29// - Release operations like unlocking a mutex delays after the mutex is
30// unlocked
31// These are more likely to expose interesting (rare) thread interleavings.
32// For example, delaying a thread that unlocks a mutex from running to allow
33// newly woken thread to execute before the unlocking thread would normally
34// execute.
35//
36// TODO:
37// - Move the adaptive delay implementation into sanitizer_common so that
38// ASAN can also leverage it in pthread_* interceptors
39// - Integrate into other interceptors like libdispatch.
40struct AdaptiveDelay {
41 ALWAYS_INLINE static void Init() { InitImpl(); }
42
43 ALWAYS_INLINE static void SyncOp() {
44 if (!is_adaptive_delay_enabled)
45 return;
46 SyncOpImpl();
47 }
48
49 ALWAYS_INLINE static void AtomicOpFence(int mo) {
50 if (!is_adaptive_delay_enabled)
51 return;
52 AtomicOpFenceImpl(mo);
53 }
54
55 ALWAYS_INLINE static void AtomicOpAddr(__sanitizer::uptr addr, int mo) {
56 if (!is_adaptive_delay_enabled)
57 return;
58 AtomicOpAddrImpl(addr, mo);
59 }
60
61 ALWAYS_INLINE static void AfterThreadCreation() {
62 if (!is_adaptive_delay_enabled)
63 return;
64 AfterThreadCreationImpl();
65 }
66
67 ALWAYS_INLINE static void BeforeChildThreadRuns() {
68 if (!is_adaptive_delay_enabled)
69 return;
70 BeforeChildThreadRunsImpl();
71 }
72
73 private:
74 static void InitImpl();
75
76 static void SyncOpImpl();
77
78 static void AtomicOpFenceImpl(int mo);
79 static void AtomicOpAddrImpl(__sanitizer::uptr addr, int mo);
80
81 static void AfterThreadCreationImpl();
82 static void BeforeChildThreadRunsImpl();
83
84 static bool is_adaptive_delay_enabled;
85};
86
87// The runtime defines cur_thread() to retrieve TLS thread state, and it
88// takes care of platform specific implementation details. The AdaptiveDelay
89// implementation stores per-thread data in this struct, which is embedded
90// in cur_thread().
91struct AdaptiveDelayState {
92 // For the adaptive delay implementation
93 // Sliding window delay tracking: 2 buckets of 30 seconds each
94 u64 delay_buckets_ns_[2]; // [0] = older 30s, [1] = newer 30s
95 u64 bucket_start_ns_; // When current bucket (index 1) started
96 u64 bucket0_window_ns; // 0ns before the first bucket has rolled, and set to
97 // the bucket window time after This handles the case
98 // where, before the program has ran one bucket window
99 // duration, we should not include the previous bucket
100 // duration in the overhead percent calculation.
101 unsigned int tls_random_seed_;
102 bool tls_initialized_;
103};
104
105// Fixed-point arithmetic type that mimics floating point operations
106class Percent {
107 using u32 = __sanitizer::u32;
108 using u64 = __sanitizer::u64;
109
110 u32 bp_{}; // basis points (0-10000 represents 0.0-1.0)
111 bool is_valid_{};
112
113 static constexpr u32 kBasisPointsPerUnit = 10000;
114
115 Percent(u32 bp, bool is_valid) : bp_(bp), is_valid_(is_valid) {}
116
117 public:
118 Percent() = default;
119 Percent(const Percent&) = default;
120 Percent& operator=(const Percent&) = default;
121 Percent(Percent&&) = default;
122 Percent& operator=(Percent&&) = default;
123
124 static Percent FromPct(u32 pct) { return Percent{pct * 100, true}; }
125 static Percent FromRatio(u64 numerator, u64 denominator) {
126 if (denominator == 0)
127 return Percent{0, false};
128 // Avoid overflow: scale down if needed
129 if (numerator > UINT64_MAX / kBasisPointsPerUnit) {
130 return Percent{(u32)((numerator / denominator) * kBasisPointsPerUnit),
131 true};
132 }
133 return Percent{(u32)((numerator * kBasisPointsPerUnit) / denominator),
134 true};
135 }
136
137 bool IsValid() const { return is_valid_; }
138
139 // Returns true with probability equal to the percentage.
140 bool RandomCheck(u32* seed) const {
141 return (Rand(seed) % kBasisPointsPerUnit) < bp_;
142 }
143
144 int GetPct() const { return bp_ / 100; }
145 int GetBasisPoints() const { return bp_; }
146
147 bool operator==(const Percent& other) const { return bp_ == other.bp_; }
148 bool operator!=(const Percent& other) const { return bp_ != other.bp_; }
149 bool operator<(const Percent& other) const { return bp_ < other.bp_; }
150 bool operator>(const Percent& other) const { return bp_ > other.bp_; }
151 bool operator<=(const Percent& other) const { return bp_ <= other.bp_; }
152 bool operator>=(const Percent& other) const { return bp_ >= other.bp_; }
153
154 Percent operator-(const Percent& other) const {
155 if (!is_valid_ || !other.is_valid_)
156 return Percent{0, false};
157 if (bp_ < other.bp_)
158 return Percent{0, false};
159 return Percent{bp_ - other.bp_, true};
160 }
161
162 Percent operator/(const Percent& other) const {
163 if (!is_valid_ || !other.is_valid_)
164 return Percent{0, false};
165 if (other.bp_ == 0)
166 return Percent{0, false};
167 return Percent{(bp_ * kBasisPointsPerUnit) / other.bp_, true};
168 }
169};
170
171} // namespace __tsan
172
173#endif // TSAN_ADAPTIVE_DELAY_H
lib/libtsan/tsan_flags.cpp+1-1
......@@ -37,7 +37,7 @@ inline bool FlagHandler<LockDuringWriteSetting>::Parse(const char *value) {
3737 *t_ = kNoLockDuringWritesAllProcesses;
3838 return true;
3939 }
40 Printf("ERROR: Invalid value for signal handler option: '%s'\n", value);
40 Printf("ERROR: Invalid value for lock_during_write option: '%s'\n", value);
4141 return false;
4242}
4343
lib/libtsan/tsan_flags.inc+27
......@@ -92,3 +92,30 @@ TSAN_FLAG(LockDuringWriteSetting, lock_during_write, kLockDuringAllWrites,
9292 "\"disable_for_all_processes\" - don't lock during all writes in "
9393 "the current process and it's children processes.")
9494#endif
95
96TSAN_FLAG(bool, enable_adaptive_delay, false,
97 "Enable adaptive delay injection to expose data races. When "
98 "enabled, delays are strategically injected at synchronization "
99 "points, atomic operations, and thread lifecycle events to increase "
100 "the likelihood of exposing races while maintaining a configurable "
101 "overhead budget.")
102
103TSAN_FLAG(
104 int, adaptive_delay_aggressiveness, 25,
105 "Controls delay injection intensity for race detection. Higher values "
106 "inject more delays to expose races. Suggested values: 10 (minimal delay), "
107 "50 (moderate delay), 200 (aggressive). "
108 "This is a tuning parameter; actual overhead varies by workload and "
109 "platform.")
110TSAN_FLAG(int, adaptive_delay_relaxed_sample_rate, 10000,
111 "Sample 1 in N relaxed atomic operations for delay")
112TSAN_FLAG(int, adaptive_delay_sync_atomic_sample_rate, 100,
113 "Sample 1 in N acquire/release/seq_cst atomic operations for delay")
114TSAN_FLAG(int, adaptive_delay_mutex_sample_rate, 10,
115 "Sample 1 in N mutex/cv operations for delay")
116TSAN_FLAG(const char*, adaptive_delay_max_atomic, "sleep_us=50",
117 "Delay for atomic operations: 'spin=N' (max N spins), 'yield', or "
118 "'sleep_us=N' (max N>0 us sleep)")
119TSAN_FLAG(const char*, adaptive_delay_max_sync, "sleep_us=500",
120 "Delay for sync operations: 'spin=N' (max N spins), 'yield', or "
121 "'sleep_us=N' (max N>0 us sleep)")
lib/libtsan/tsan_interceptors_posix.cpp+24-2
......@@ -34,6 +34,7 @@
3434#if SANITIZER_APPLE && !SANITIZER_GO
3535# include "tsan_flags.h"
3636#endif
37#include "tsan_adaptive_delay.h"
3738#include "tsan_interceptors.h"
3839#include "tsan_interface.h"
3940#include "tsan_mman.h"
......@@ -1065,6 +1066,9 @@ extern "C" void *__tsan_thread_start_func(void *arg) {
10651066 ThreadStart(thr, p->tid, GetTid(), ThreadType::Regular);
10661067 p->started.Post();
10671068 }
1069
1070 AdaptiveDelay::BeforeChildThreadRuns();
1071
10681072 void *res = callback(param);
10691073 // Prevent the callback from being tail called,
10701074 // it mixes up stack traces.
......@@ -1128,6 +1132,7 @@ TSAN_INTERCEPTOR(int, pthread_create,
11281132 }
11291133 if (attr == &myattr)
11301134 pthread_attr_destroy(&myattr);
1135 AdaptiveDelay::AfterThreadCreation();
11311136 return res;
11321137}
11331138
......@@ -1423,6 +1428,7 @@ TSAN_INTERCEPTOR(int, pthread_mutex_destroy, void *m) {
14231428TSAN_INTERCEPTOR(int, pthread_mutex_lock, void *m) {
14241429 SCOPED_TSAN_INTERCEPTOR(pthread_mutex_lock, m);
14251430 MutexPreLock(thr, pc, (uptr)m);
1431 AdaptiveDelay::SyncOp();
14261432 int res = BLOCK_REAL(pthread_mutex_lock)(m);
14271433 if (res == errno_EOWNERDEAD)
14281434 MutexRepair(thr, pc, (uptr)m);
......@@ -1435,6 +1441,7 @@ TSAN_INTERCEPTOR(int, pthread_mutex_lock, void *m) {
14351441
14361442TSAN_INTERCEPTOR(int, pthread_mutex_trylock, void *m) {
14371443 SCOPED_TSAN_INTERCEPTOR(pthread_mutex_trylock, m);
1444 AdaptiveDelay::SyncOp();
14381445 int res = REAL(pthread_mutex_trylock)(m);
14391446 if (res == errno_EOWNERDEAD)
14401447 MutexRepair(thr, pc, (uptr)m);
......@@ -1446,6 +1453,7 @@ TSAN_INTERCEPTOR(int, pthread_mutex_trylock, void *m) {
14461453#if !SANITIZER_APPLE
14471454TSAN_INTERCEPTOR(int, pthread_mutex_timedlock, void *m, void *abstime) {
14481455 SCOPED_TSAN_INTERCEPTOR(pthread_mutex_timedlock, m, abstime);
1456 AdaptiveDelay::SyncOp();
14491457 int res = REAL(pthread_mutex_timedlock)(m, abstime);
14501458 if (res == 0) {
14511459 MutexPostLock(thr, pc, (uptr)m, MutexFlagTryLock);
......@@ -1458,6 +1466,7 @@ TSAN_INTERCEPTOR(int, pthread_mutex_unlock, void *m) {
14581466 SCOPED_TSAN_INTERCEPTOR(pthread_mutex_unlock, m);
14591467 MutexUnlock(thr, pc, (uptr)m);
14601468 int res = REAL(pthread_mutex_unlock)(m);
1469 AdaptiveDelay::SyncOp();
14611470 if (res == errno_EINVAL)
14621471 MutexInvalidAccess(thr, pc, (uptr)m);
14631472 return res;
......@@ -1468,6 +1477,7 @@ TSAN_INTERCEPTOR(int, pthread_mutex_clocklock, void *m,
14681477 __sanitizer_clockid_t clock, void *abstime) {
14691478 SCOPED_TSAN_INTERCEPTOR(pthread_mutex_clocklock, m, clock, abstime);
14701479 MutexPreLock(thr, pc, (uptr)m);
1480 AdaptiveDelay::SyncOp();
14711481 int res = BLOCK_REAL(pthread_mutex_clocklock)(m, clock, abstime);
14721482 if (res == errno_EOWNERDEAD)
14731483 MutexRepair(thr, pc, (uptr)m);
......@@ -1486,6 +1496,7 @@ TSAN_INTERCEPTOR(int, pthread_mutex_clocklock, void *m,
14861496TSAN_INTERCEPTOR(int, __pthread_mutex_lock, void *m) {
14871497 SCOPED_TSAN_INTERCEPTOR(__pthread_mutex_lock, m);
14881498 MutexPreLock(thr, pc, (uptr)m);
1499 AdaptiveDelay::SyncOp();
14891500 int res = BLOCK_REAL(__pthread_mutex_lock)(m);
14901501 if (res == errno_EOWNERDEAD)
14911502 MutexRepair(thr, pc, (uptr)m);
......@@ -1500,6 +1511,7 @@ TSAN_INTERCEPTOR(int, __pthread_mutex_unlock, void *m) {
15001511 SCOPED_TSAN_INTERCEPTOR(__pthread_mutex_unlock, m);
15011512 MutexUnlock(thr, pc, (uptr)m);
15021513 int res = REAL(__pthread_mutex_unlock)(m);
1514 AdaptiveDelay::SyncOp();
15031515 if (res == errno_EINVAL)
15041516 MutexInvalidAccess(thr, pc, (uptr)m);
15051517 return res;
......@@ -1529,6 +1541,7 @@ TSAN_INTERCEPTOR(int, pthread_spin_destroy, void *m) {
15291541TSAN_INTERCEPTOR(int, pthread_spin_lock, void *m) {
15301542 SCOPED_TSAN_INTERCEPTOR(pthread_spin_lock, m);
15311543 MutexPreLock(thr, pc, (uptr)m);
1544 AdaptiveDelay::SyncOp();
15321545 int res = BLOCK_REAL(pthread_spin_lock)(m);
15331546 if (res == 0) {
15341547 MutexPostLock(thr, pc, (uptr)m);
......@@ -1538,6 +1551,7 @@ TSAN_INTERCEPTOR(int, pthread_spin_lock, void *m) {
15381551
15391552TSAN_INTERCEPTOR(int, pthread_spin_trylock, void *m) {
15401553 SCOPED_TSAN_INTERCEPTOR(pthread_spin_trylock, m);
1554 AdaptiveDelay::SyncOp();
15411555 int res = REAL(pthread_spin_trylock)(m);
15421556 if (res == 0) {
15431557 MutexPostLock(thr, pc, (uptr)m, MutexFlagTryLock);
......@@ -1549,6 +1563,7 @@ TSAN_INTERCEPTOR(int, pthread_spin_unlock, void *m) {
15491563 SCOPED_TSAN_INTERCEPTOR(pthread_spin_unlock, m);
15501564 MutexUnlock(thr, pc, (uptr)m);
15511565 int res = REAL(pthread_spin_unlock)(m);
1566 AdaptiveDelay::SyncOp();
15521567 return res;
15531568}
15541569#endif
......@@ -1574,6 +1589,7 @@ TSAN_INTERCEPTOR(int, pthread_rwlock_destroy, void *m) {
15741589TSAN_INTERCEPTOR(int, pthread_rwlock_rdlock, void *m) {
15751590 SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_rdlock, m);
15761591 MutexPreReadLock(thr, pc, (uptr)m);
1592 AdaptiveDelay::SyncOp();
15771593 int res = REAL(pthread_rwlock_rdlock)(m);
15781594 if (res == 0) {
15791595 MutexPostReadLock(thr, pc, (uptr)m);
......@@ -1583,6 +1599,7 @@ TSAN_INTERCEPTOR(int, pthread_rwlock_rdlock, void *m) {
15831599
15841600TSAN_INTERCEPTOR(int, pthread_rwlock_tryrdlock, void *m) {
15851601 SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_tryrdlock, m);
1602 AdaptiveDelay::SyncOp();
15861603 int res = REAL(pthread_rwlock_tryrdlock)(m);
15871604 if (res == 0) {
15881605 MutexPostReadLock(thr, pc, (uptr)m, MutexFlagTryLock);
......@@ -1593,6 +1610,7 @@ TSAN_INTERCEPTOR(int, pthread_rwlock_tryrdlock, void *m) {
15931610#if !SANITIZER_APPLE
15941611TSAN_INTERCEPTOR(int, pthread_rwlock_timedrdlock, void *m, void *abstime) {
15951612 SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_timedrdlock, m, abstime);
1613 AdaptiveDelay::SyncOp();
15961614 int res = REAL(pthread_rwlock_timedrdlock)(m, abstime);
15971615 if (res == 0) {
15981616 MutexPostReadLock(thr, pc, (uptr)m);
......@@ -1604,6 +1622,7 @@ TSAN_INTERCEPTOR(int, pthread_rwlock_timedrdlock, void *m, void *abstime) {
16041622TSAN_INTERCEPTOR(int, pthread_rwlock_wrlock, void *m) {
16051623 SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_wrlock, m);
16061624 MutexPreLock(thr, pc, (uptr)m);
1625 AdaptiveDelay::SyncOp();
16071626 int res = BLOCK_REAL(pthread_rwlock_wrlock)(m);
16081627 if (res == 0) {
16091628 MutexPostLock(thr, pc, (uptr)m);
......@@ -1613,6 +1632,7 @@ TSAN_INTERCEPTOR(int, pthread_rwlock_wrlock, void *m) {
16131632
16141633TSAN_INTERCEPTOR(int, pthread_rwlock_trywrlock, void *m) {
16151634 SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_trywrlock, m);
1635 AdaptiveDelay::SyncOp();
16161636 int res = REAL(pthread_rwlock_trywrlock)(m);
16171637 if (res == 0) {
16181638 MutexPostLock(thr, pc, (uptr)m, MutexFlagTryLock);
......@@ -1623,6 +1643,7 @@ TSAN_INTERCEPTOR(int, pthread_rwlock_trywrlock, void *m) {
16231643#if !SANITIZER_APPLE
16241644TSAN_INTERCEPTOR(int, pthread_rwlock_timedwrlock, void *m, void *abstime) {
16251645 SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_timedwrlock, m, abstime);
1646 AdaptiveDelay::SyncOp();
16261647 int res = REAL(pthread_rwlock_timedwrlock)(m, abstime);
16271648 if (res == 0) {
16281649 MutexPostLock(thr, pc, (uptr)m, MutexFlagTryLock);
......@@ -1635,6 +1656,7 @@ TSAN_INTERCEPTOR(int, pthread_rwlock_unlock, void *m) {
16351656 SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_unlock, m);
16361657 MutexReadOrWriteUnlock(thr, pc, (uptr)m);
16371658 int res = REAL(pthread_rwlock_unlock)(m);
1659 AdaptiveDelay::SyncOp();
16381660 return res;
16391661}
16401662
......@@ -2574,9 +2596,9 @@ static void HandleRecvmsg(ThreadState *thr, uptr pc,
25742596
25752597#define COMMON_INTERCEPTOR_DLOPEN(filename, flag) \
25762598 ({ \
2577 CheckNoDeepBind(filename, flag); \
2599 OnDlOpen(filename, flag); \
25782600 ThreadIgnoreBegin(thr, 0); \
2579 void *res = REAL(dlopen)(filename, flag); \
2601 void* res = REAL(dlopen)(filename, flag); \
25802602 ThreadIgnoreEnd(thr); \
25812603 res; \
25822604 })
lib/libtsan/tsan_interface_ann.cpp+9-5
......@@ -9,17 +9,19 @@
99// This file is a part of ThreadSanitizer (TSan), a race detector.
1010//
1111//===----------------------------------------------------------------------===//
12#include "sanitizer_common/sanitizer_libc.h"
12#include "tsan_interface_ann.h"
13
1314#include "sanitizer_common/sanitizer_internal_defs.h"
15#include "sanitizer_common/sanitizer_libc.h"
1416#include "sanitizer_common/sanitizer_placement_new.h"
1517#include "sanitizer_common/sanitizer_stacktrace.h"
1618#include "sanitizer_common/sanitizer_vector.h"
17#include "tsan_interface_ann.h"
18#include "tsan_report.h"
19#include "tsan_rtl.h"
20#include "tsan_mman.h"
19#include "tsan_adaptive_delay.h"
2120#include "tsan_flags.h"
21#include "tsan_mman.h"
2222#include "tsan_platform.h"
23#include "tsan_report.h"
24#include "tsan_rtl.h"
2325
2426#define CALLERPC ((uptr)__builtin_return_address(0))
2527
......@@ -370,6 +372,7 @@ void __tsan_mutex_pre_lock(void *m, unsigned flagz) {
370372 }
371373 ThreadIgnoreBegin(thr, 0);
372374 ThreadIgnoreSyncBegin(thr, 0);
375 AdaptiveDelay::SyncOp();
373376}
374377
375378INTERFACE_ATTRIBUTE
......@@ -402,6 +405,7 @@ int __tsan_mutex_pre_unlock(void *m, unsigned flagz) {
402405
403406INTERFACE_ATTRIBUTE
404407void __tsan_mutex_post_unlock(void *m, unsigned flagz) {
408 AdaptiveDelay::SyncOp();
405409 SCOPED_ANNOTATION(__tsan_mutex_post_unlock);
406410 ThreadIgnoreSyncEnd(thr);
407411 ThreadIgnoreEnd(thr);
lib/libtsan/tsan_interface_atomic.cpp+12
......@@ -21,6 +21,7 @@
2121#include "sanitizer_common/sanitizer_mutex.h"
2222#include "sanitizer_common/sanitizer_placement_new.h"
2323#include "sanitizer_common/sanitizer_stacktrace.h"
24#include "tsan_adaptive_delay.h"
2425#include "tsan_flags.h"
2526#include "tsan_interface.h"
2627#include "tsan_rtl.h"
......@@ -520,8 +521,19 @@ static morder to_morder(int mo) {
520521 return res;
521522}
522523
524template <class... Types>
525ALWAYS_INLINE auto AtomicDelayImpl(morder mo, Types... args) {
526 AdaptiveDelay::AtomicOpFence(mo);
527}
528
529template <class AddrType, class... Types>
530ALWAYS_INLINE auto AtomicDelayImpl(morder mo, AddrType addr, Types... args) {
531 AdaptiveDelay::AtomicOpAddr((uptr)addr, (int)mo);
532}
533
523534template <class Op, class... Types>
524535ALWAYS_INLINE auto AtomicImpl(morder mo, Types... args) {
536 AtomicDelayImpl(mo, args...);
525537 ThreadState *const thr = cur_thread();
526538 ProcessPendingSignals(thr);
527539 if (UNLIKELY(thr->ignore_sync || thr->ignore_interceptors))
lib/libtsan/tsan_platform.h+10-7
......@@ -404,7 +404,7 @@ struct MappingRiscv64_39 {
404404 static const uptr kHeapMemBeg = 0x2c00000000ull;
405405 static const uptr kHeapMemEnd = 0x2c00000000ull;
406406 static const uptr kHiAppMemBeg = 0x3c00000000ull;
407 static const uptr kHiAppMemEnd = 0x3fffffffffull;
407 static const uptr kHiAppMemEnd = 0x4000000000ull;
408408 static const uptr kShadowMsk = 0x3800000000ull;
409409 static const uptr kShadowXor = 0x0800000000ull;
410410 static const uptr kShadowAdd = 0x0000000000ull;
......@@ -434,7 +434,7 @@ struct MappingRiscv64_48 {
434434 static const uptr kHeapMemBeg = 0x5a0000000000ull;
435435 static const uptr kHeapMemEnd = 0x5a0000000000ull;
436436 static const uptr kHiAppMemBeg = 0x7a0000000000ull;
437 static const uptr kHiAppMemEnd = 0x7fffffffffffull;
437 static const uptr kHiAppMemEnd = 0x800000000000ull;
438438 static const uptr kShadowMsk = 0x700000000000ull;
439439 static const uptr kShadowXor = 0x100000000000ull;
440440 static const uptr kShadowAdd = 0x000000000000ull;
......@@ -738,13 +738,16 @@ struct MappingGoRiscv64_48 {
738738Go on linux/s390x
7397390000 0000 1000 - 1000 0000 0000: executable and heap - 16 TiB
7407401000 0000 0000 - 4000 0000 0000: -
7414000 0000 0000 - 6000 0000 0000: shadow - 64TiB (4 * app)
7426000 0000 0000 - 9000 0000 0000: -
7439000 0000 0000 - 9800 0000 0000: metainfo - 8TiB (0.5 * app)
7414000 0000 0000 - 6000 0000 0000: shadow - 32 TiB (2 * app)
7426000 0000 0000 - 7000 0000 0000: -
7437000 0000 0000 - 7800 0000 0000: metainfo - 8 TiB (0.5 * app)
7447800 0000 0000 - 8000 0000 0000: -
744745*/
745746struct MappingGoS390x {
746 static const uptr kMetaShadowBeg = 0x900000000000ull;
747 static const uptr kMetaShadowEnd = 0x980000000000ull;
747 // Keep the mapping below 2^47 for QEMU linux-user on x86-64 hosts with
748 // four-level page tables.
749 static const uptr kMetaShadowBeg = 0x700000000000ull;
750 static const uptr kMetaShadowEnd = 0x780000000000ull;
748751 static const uptr kShadowBeg = 0x400000000000ull;
749752 static const uptr kShadowEnd = 0x600000000000ull;
750753 static const uptr kLoAppMemBeg = 0x000000001000ull;
lib/libtsan/tsan_platform_linux.cpp+12
......@@ -27,6 +27,18 @@
2727#include "tsan_platform.h"
2828#include "tsan_rtl.h"
2929
30#if SANITIZER_NETBSD
31# // for __lwp_gettcb_fast() / __lwp_getprivate_fast()
32# define _RTLD_SOURCE
33# include <sys/types.h>
34# include <machine/mcontext.h>
35# undef _RTLD_SOURCE
36# include <sys/param.h>
37# if __NetBSD_Version__ >= 1099001200
38# include <machine/lwp_private.h>
39# endif
40#endif
41
3042#include <fcntl.h>
3143#include <pthread.h>
3244#include <signal.h>
lib/libtsan/tsan_report.cpp+3-2
......@@ -317,8 +317,9 @@ void PrintReport(const ReportDesc *rep) {
317317 } else {
318318 PrintStack(rep->stacks[i]);
319319 if (i == 0)
320 Printf(" Hint: use TSAN_OPTIONS=second_deadlock_stack=1 "
321 "to get more informative warning message\n\n");
320 Printf(
321 " HINT: use TSAN_OPTIONS=second_deadlock_stack=1 "
322 "to get more informative warning message\n\n");
322323 }
323324 }
324325 } else {
lib/libtsan/tsan_rtl.cpp+5
......@@ -21,6 +21,7 @@
2121#include "sanitizer_common/sanitizer_placement_new.h"
2222#include "sanitizer_common/sanitizer_stackdepot.h"
2323#include "sanitizer_common/sanitizer_symbolizer.h"
24#include "tsan_adaptive_delay.h"
2425#include "tsan_defs.h"
2526#include "tsan_interface.h"
2627#include "tsan_mman.h"
......@@ -775,6 +776,10 @@ void Initialize(ThreadState *thr) {
775776 while (__tsan_resumed == 0) {}
776777 }
777778
779#if !SANITIZER_GO
780 AdaptiveDelay::Init();
781#endif
782
778783 OnInitialize();
779784}
780785
lib/libtsan/tsan_rtl.h+3
......@@ -34,6 +34,7 @@
3434#include "sanitizer_common/sanitizer_suppressions.h"
3535#include "sanitizer_common/sanitizer_thread_registry.h"
3636#include "sanitizer_common/sanitizer_vector.h"
37#include "tsan_adaptive_delay.h"
3738#include "tsan_defs.h"
3839#include "tsan_flags.h"
3940#include "tsan_ignoreset.h"
......@@ -240,6 +241,8 @@ struct alignas(SANITIZER_CACHE_LINE_SIZE) ThreadState {
240241 bool in_internal_write_call;
241242#endif
242243
244 AdaptiveDelayState adaptive_delay_state;
245
243246 explicit ThreadState(Tid tid);
244247};
245248
lib/libtsan/ubsan/ubsan_flags.h+4
......@@ -41,6 +41,10 @@ extern "C" {
4141// override the default flag values.
4242SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
4343const char *__ubsan_default_options();
44// Users may provide their own implementation of __ubsan_default_suppressions to
45// override the default suppression values.
46SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE const char *
47__ubsan_default_suppressions();
4448} // extern "C"
4549
4650#endif // UBSAN_FLAGS_H
src/libs/libtsan.zig+1
......@@ -350,6 +350,7 @@ fn addCcArgs(target: *const std.Target, args: *std.array_list.Managed([]const u8
350350}
351351
352352const tsan_sources = [_][]const u8{
353 "tsan_adaptive_delay.cpp",
353354 "tsan_debugging.cpp",
354355 "tsan_external.cpp",
355356 "tsan_fd.cpp",