//===-- tsan_defs.h ---------------------------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file is a part of ThreadSanitizer (TSan), a race detector. // //===----------------------------------------------------------------------===// #ifndef TSAN_DEFS_H #define TSAN_DEFS_H #include "sanitizer_common/sanitizer_internal_defs.h" #include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_mutex.h" #include "ubsan/ubsan_platform.h" #ifndef TSAN_VECTORIZE # define TSAN_VECTORIZE __SSE4_2__ #endif #if TSAN_VECTORIZE // transitively includes , // and it's prohibited to include std headers into tsan runtime. // So we do this dirty trick. # define _MM_MALLOC_H_INCLUDED # define __MM_MALLOC_H # include # include # define VECTOR_ALIGNED ALIGNED(16) typedef __m128i m128; #else # define VECTOR_ALIGNED #endif // Setup defaults for compile definitions. #ifndef TSAN_NO_HISTORY # define TSAN_NO_HISTORY 0 #endif #ifndef TSAN_CONTAINS_UBSAN # if CAN_SANITIZE_UB && !SANITIZER_GO # define TSAN_CONTAINS_UBSAN 1 # else # define TSAN_CONTAINS_UBSAN 0 # endif #endif namespace __tsan { constexpr uptr kByteBits = 8; // Thread slot ID. enum class Sid : u8 {}; constexpr uptr kThreadSlotCount = 256; constexpr Sid kFreeSid = static_cast(255); // Abstract time unit, vector clock element. enum class Epoch : u16 {}; constexpr uptr kEpochBits = 14; constexpr Epoch kEpochZero = static_cast(0); constexpr Epoch kEpochOver = static_cast(1 << kEpochBits); constexpr Epoch kEpochLast = static_cast((1 << kEpochBits) - 1); inline Epoch EpochInc(Epoch epoch) { return static_cast(static_cast(epoch) + 1); } inline bool EpochOverflow(Epoch epoch) { return epoch == kEpochOver; } const uptr kShadowStackSize = 64 * 1024; // Count of shadow values in a shadow cell. const uptr kShadowCnt = 4; // That many user bytes are mapped onto a single shadow cell. const uptr kShadowCell = 8; // Single shadow value. enum class RawShadow : u32 {}; const uptr kShadowSize = sizeof(RawShadow); // Shadow memory is kShadowMultiplier times larger than user memory. const uptr kShadowMultiplier = kShadowSize * kShadowCnt / kShadowCell; // That many user bytes are mapped onto a single meta shadow cell. // Must be less or equal to minimal memory allocator alignment. const uptr kMetaShadowCell = 8; // Size of a single meta shadow value (u32). const uptr kMetaShadowSize = 4; // All addresses and PCs are assumed to be compressable to that many bits. const uptr kCompressedAddrBits = 44; #if TSAN_NO_HISTORY const bool kCollectHistory = false; #else const bool kCollectHistory = true; #endif // The following "build consistency" machinery ensures that all source files // are built in the same configuration. Inconsistent builds lead to // hard to debug crashes. #if SANITIZER_DEBUG void build_consistency_debug(); #else void build_consistency_release(); #endif static inline void USED build_consistency() { #if SANITIZER_DEBUG build_consistency_debug(); #else build_consistency_release(); #endif } template T min(T a, T b) { return a < b ? a : b; } template T max(T a, T b) { return a > b ? a : b; } template T RoundUp(T p, u64 align) { DCHECK_EQ(align & (align - 1), 0); return (T)(((u64)p + align - 1) & ~(align - 1)); } template T RoundDown(T p, u64 align) { DCHECK_EQ(align & (align - 1), 0); return (T)((u64)p & ~(align - 1)); } // Zeroizes high part, returns 'bits' lsb bits. template T GetLsb(T v, int bits) { return (T)((u64)v & ((1ull << bits) - 1)); } struct MD5Hash { u64 hash[2]; bool operator==(const MD5Hash &other) const; }; MD5Hash md5_hash(const void *data, uptr size); struct Processor; struct ThreadState; class ThreadContext; struct TidSlot; struct Context; struct ReportStack; class ReportDesc; class RegionAlloc; struct Trace; struct TracePart; typedef uptr AccessType; enum : AccessType { kAccessWrite = 0, kAccessRead = 1 << 0, kAccessAtomic = 1 << 1, kAccessVptr = 1 << 2, // read or write of an object virtual table pointer kAccessFree = 1 << 3, // synthetic memory access during memory freeing kAccessExternalPC = 1 << 4, // access PC can have kExternalPCBit set kAccessCheckOnly = 1 << 5, // check for races, but don't store kAccessNoRodata = 1 << 6, // don't check for .rodata marker kAccessSlotLocked = 1 << 7, // memory access with TidSlot locked }; // Descriptor of user's memory block. struct MBlock { u64 siz : 48; u64 tag : 16; StackID stk; Tid tid; }; COMPILER_CHECK(sizeof(MBlock) == 16); enum ExternalTag : uptr { kExternalTagNone = 0, kExternalTagSwiftModifyingAccess = 1, kExternalTagFirstUserAvailable = 2, kExternalTagMax = 1024, // Don't set kExternalTagMax over 65,536, since MBlock only stores tags // as 16-bit values, see tsan_defs.h. }; enum { MutexTypeReport = MutexLastCommon, MutexTypeSyncVar, MutexTypeAnnotations, MutexTypeAtExit, MutexTypeFired, MutexTypeRacy, MutexTypeGlobalProc, MutexTypeInternalAlloc, MutexTypeTrace, MutexTypeSlot, MutexTypeSlots, }; } // namespace __tsan #endif // TSAN_DEFS_H