1251034Sed//=-- lsan_common.h -------------------------------------------------------===// 2251034Sed// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6251034Sed// 7251034Sed//===----------------------------------------------------------------------===// 8251034Sed// 9251034Sed// This file is a part of LeakSanitizer. 10251034Sed// Private LSan header. 11251034Sed// 12251034Sed//===----------------------------------------------------------------------===// 13251034Sed 14251034Sed#ifndef LSAN_COMMON_H 15251034Sed#define LSAN_COMMON_H 16251034Sed 17274201Sdim#include "sanitizer_common/sanitizer_allocator.h" 18251034Sed#include "sanitizer_common/sanitizer_common.h" 19251034Sed#include "sanitizer_common/sanitizer_internal_defs.h" 20251034Sed#include "sanitizer_common/sanitizer_platform.h" 21288943Sdim#include "sanitizer_common/sanitizer_stoptheworld.h" 22251034Sed#include "sanitizer_common/sanitizer_symbolizer.h" 23251034Sed 24353358Sdim// LeakSanitizer relies on some Glibc's internals (e.g. TLS machinery) on Linux. 25353358Sdim// Also, LSan doesn't like 32 bit architectures 26321369Sdim// because of "small" (4 bytes) pointer size that leads to high false negative 27321369Sdim// ratio on large leaks. But we still want to have it for some 32 bit arches 28321369Sdim// (e.g. x86), see https://github.com/google/sanitizers/issues/403. 29327952Sdim// To enable LeakSanitizer on a new architecture, one needs to implement the 30327952Sdim// internal_clone function as well as (probably) adjust the TLS machinery for 31327952Sdim// the new architecture inside the sanitizer library. 32321369Sdim#if (SANITIZER_LINUX && !SANITIZER_ANDROID || SANITIZER_MAC) && \ 33321369Sdim (SANITIZER_WORDSIZE == 64) && \ 34321369Sdim (defined(__x86_64__) || defined(__mips64) || defined(__aarch64__) || \ 35321369Sdim defined(__powerpc64__)) 36251034Sed#define CAN_SANITIZE_LEAKS 1 37321369Sdim#elif defined(__i386__) && \ 38321369Sdim (SANITIZER_LINUX && !SANITIZER_ANDROID || SANITIZER_MAC) 39321369Sdim#define CAN_SANITIZE_LEAKS 1 40321369Sdim#elif defined(__arm__) && \ 41321369Sdim SANITIZER_LINUX && !SANITIZER_ANDROID 42321369Sdim#define CAN_SANITIZE_LEAKS 1 43353358Sdim#elif SANITIZER_NETBSD 44353358Sdim#define CAN_SANITIZE_LEAKS 1 45251034Sed#else 46251034Sed#define CAN_SANITIZE_LEAKS 0 47251034Sed#endif 48251034Sed 49280031Sdimnamespace __sanitizer { 50280031Sdimclass FlagParser; 51341825Sdimclass ThreadRegistry; 52309124Sdimstruct DTLS; 53280031Sdim} 54280031Sdim 55251034Sednamespace __lsan { 56251034Sed 57251034Sed// Chunk tags. 58251034Sedenum ChunkTag { 59251034Sed kDirectlyLeaked = 0, // default 60251034Sed kIndirectlyLeaked = 1, 61274201Sdim kReachable = 2, 62274201Sdim kIgnored = 3 63251034Sed}; 64251034Sed 65321369Sdimconst u32 kInvalidTid = (u32) -1; 66321369Sdim 67251034Sedstruct Flags { 68280031Sdim#define LSAN_FLAG(Type, Name, DefaultValue, Description) Type Name; 69280031Sdim#include "lsan_flags.inc" 70280031Sdim#undef LSAN_FLAG 71280031Sdim 72280031Sdim void SetDefaults(); 73251034Sed uptr pointer_alignment() const { 74251034Sed return use_unaligned ? 1 : sizeof(uptr); 75251034Sed } 76251034Sed}; 77251034Sed 78251034Sedextern Flags lsan_flags; 79251034Sedinline Flags *flags() { return &lsan_flags; } 80280031Sdimvoid RegisterLsanFlags(FlagParser *parser, Flags *f); 81251034Sed 82251034Sedstruct Leak { 83276789Sdim u32 id; 84251034Sed uptr hit_count; 85251034Sed uptr total_size; 86251034Sed u32 stack_trace_id; 87251034Sed bool is_directly_leaked; 88274201Sdim bool is_suppressed; 89251034Sed}; 90251034Sed 91276789Sdimstruct LeakedObject { 92276789Sdim u32 leak_id; 93276789Sdim uptr addr; 94276789Sdim uptr size; 95276789Sdim}; 96276789Sdim 97251034Sed// Aggregates leaks by stack trace prefix. 98251034Sedclass LeakReport { 99251034Sed public: 100341825Sdim LeakReport() {} 101276789Sdim void AddLeakedChunk(uptr chunk, u32 stack_trace_id, uptr leaked_size, 102276789Sdim ChunkTag tag); 103276789Sdim void ReportTopLeaks(uptr max_leaks); 104251034Sed void PrintSummary(); 105276789Sdim void ApplySuppressions(); 106276789Sdim uptr UnsuppressedLeakCount(); 107276789Sdim 108251034Sed private: 109276789Sdim void PrintReportForLeak(uptr index); 110276789Sdim void PrintLeakedObjectsForLeak(uptr index); 111276789Sdim 112341825Sdim u32 next_id_ = 0; 113274201Sdim InternalMmapVector<Leak> leaks_; 114276789Sdim InternalMmapVector<LeakedObject> leaked_objects_; 115251034Sed}; 116251034Sed 117274201Sdimtypedef InternalMmapVector<uptr> Frontier; 118274201Sdim 119251034Sed// Platform-specific functions. 120251034Sedvoid InitializePlatformSpecificModules(); 121274201Sdimvoid ProcessGlobalRegions(Frontier *frontier); 122274201Sdimvoid ProcessPlatformSpecificAllocations(Frontier *frontier); 123321369Sdim 124321369Sdimstruct RootRegion { 125321369Sdim uptr begin; 126321369Sdim uptr size; 127321369Sdim}; 128321369Sdim 129321369SdimInternalMmapVector<RootRegion> const *GetRootRegions(); 130321369Sdimvoid ScanRootRegion(Frontier *frontier, RootRegion const ®ion, 131321369Sdim uptr region_begin, uptr region_end, bool is_readable); 132360784Sdim// Run stoptheworld while holding any platform-specific locks, as well as the 133360784Sdim// allocator and thread registry locks. 134360784Sdimvoid LockStuffAndStopTheWorld(StopTheWorldCallback callback, void* argument); 135251034Sed 136274201Sdimvoid ScanRangeForPointers(uptr begin, uptr end, 137274201Sdim Frontier *frontier, 138251034Sed const char *region_type, ChunkTag tag); 139321369Sdimvoid ScanGlobalRange(uptr begin, uptr end, Frontier *frontier); 140251034Sed 141274201Sdimenum IgnoreObjectResult { 142274201Sdim kIgnoreObjectSuccess, 143274201Sdim kIgnoreObjectAlreadyIgnored, 144274201Sdim kIgnoreObjectInvalid 145251034Sed}; 146251034Sed 147274201Sdim// Functions called from the parent tool. 148327952Sdimconst char *MaybeCallLsanDefaultOptions(); 149280031Sdimvoid InitCommonLsan(); 150274201Sdimvoid DoLeakCheck(); 151327952Sdimvoid DoRecoverableLeakCheckVoid(); 152321369Sdimvoid DisableCounterUnderflow(); 153274201Sdimbool DisabledInThisThread(); 154251034Sed 155309124Sdim// Used to implement __lsan::ScopedDisabler. 156309124Sdimvoid DisableInThisThread(); 157309124Sdimvoid EnableInThisThread(); 158309124Sdim// Can be used to ignore memory allocated by an intercepted 159309124Sdim// function. 160309124Sdimstruct ScopedInterceptorDisabler { 161309124Sdim ScopedInterceptorDisabler() { DisableInThisThread(); } 162309124Sdim ~ScopedInterceptorDisabler() { EnableInThisThread(); } 163309124Sdim}; 164309124Sdim 165321369Sdim// According to Itanium C++ ABI array cookie is a one word containing 166321369Sdim// size of allocated array. 167321369Sdimstatic inline bool IsItaniumABIArrayCookie(uptr chunk_beg, uptr chunk_size, 168321369Sdim uptr addr) { 169321369Sdim return chunk_size == sizeof(uptr) && chunk_beg + chunk_size == addr && 170321369Sdim *reinterpret_cast<uptr *>(chunk_beg) == 0; 171321369Sdim} 172321369Sdim 173321369Sdim// According to ARM C++ ABI array cookie consists of two words: 174321369Sdim// struct array_cookie { 175321369Sdim// std::size_t element_size; // element_size != 0 176321369Sdim// std::size_t element_count; 177321369Sdim// }; 178321369Sdimstatic inline bool IsARMABIArrayCookie(uptr chunk_beg, uptr chunk_size, 179321369Sdim uptr addr) { 180321369Sdim return chunk_size == 2 * sizeof(uptr) && chunk_beg + chunk_size == addr && 181321369Sdim *reinterpret_cast<uptr *>(chunk_beg + sizeof(uptr)) == 0; 182321369Sdim} 183321369Sdim 184276789Sdim// Special case for "new T[0]" where T is a type with DTOR. 185321369Sdim// new T[0] will allocate a cookie (one or two words) for the array size (0) 186321369Sdim// and store a pointer to the end of allocated chunk. The actual cookie layout 187321369Sdim// varies between platforms according to their C++ ABI implementation. 188276789Sdiminline bool IsSpecialCaseOfOperatorNew0(uptr chunk_beg, uptr chunk_size, 189276789Sdim uptr addr) { 190321369Sdim#if defined(__arm__) 191321369Sdim return IsARMABIArrayCookie(chunk_beg, chunk_size, addr); 192321369Sdim#else 193321369Sdim return IsItaniumABIArrayCookie(chunk_beg, chunk_size, addr); 194321369Sdim#endif 195276789Sdim} 196276789Sdim 197251034Sed// The following must be implemented in the parent tool. 198251034Sed 199274201Sdimvoid ForEachChunk(ForEachChunkCallback callback, void *arg); 200274201Sdim// Returns the address range occupied by the global allocator object. 201251034Sedvoid GetAllocatorGlobalRange(uptr *begin, uptr *end); 202251034Sed// Wrappers for allocator's ForceLock()/ForceUnlock(). 203251034Sedvoid LockAllocator(); 204251034Sedvoid UnlockAllocator(); 205276789Sdim// Returns true if [addr, addr + sizeof(void *)) is poisoned. 206276789Sdimbool WordIsPoisoned(uptr addr); 207251034Sed// Wrappers for ThreadRegistry access. 208251034Sedvoid LockThreadRegistry(); 209251034Sedvoid UnlockThreadRegistry(); 210341825SdimThreadRegistry *GetThreadRegistryLocked(); 211321369Sdimbool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end, 212309124Sdim uptr *tls_begin, uptr *tls_end, uptr *cache_begin, 213309124Sdim uptr *cache_end, DTLS **dtls); 214321369Sdimvoid ForEachExtraStackRange(tid_t os_id, RangeIteratorCallback callback, 215274201Sdim void *arg); 216274201Sdim// If called from the main thread, updates the main thread's TID in the thread 217274201Sdim// registry. We need this to handle processes that fork() without a subsequent 218274201Sdim// exec(), which invalidates the recorded TID. To update it, we must call 219274201Sdim// gettid() from the main thread. Our solution is to call this function before 220274201Sdim// leak checking and also before every call to pthread_create() (to handle cases 221274201Sdim// where leak checking is initiated from a non-main thread). 222274201Sdimvoid EnsureMainThreadIDIsCorrect(); 223274201Sdim// If p points into a chunk that has been allocated to the user, returns its 224274201Sdim// user-visible address. Otherwise, returns 0. 225274201Sdimuptr PointsIntoChunk(void *p); 226274201Sdim// Returns address of user-visible chunk contained in this allocator chunk. 227274201Sdimuptr GetUserBegin(uptr chunk); 228274201Sdim// Helper for __lsan_ignore_object(). 229274201SdimIgnoreObjectResult IgnoreObjectLocked(const void *p); 230321369Sdim 231321369Sdim// Return the linker module, if valid for the platform. 232321369SdimLoadedModule *GetLinker(); 233321369Sdim 234321369Sdim// Return true if LSan has finished leak checking and reported leaks. 235321369Sdimbool HasReportedLeaks(); 236321369Sdim 237321369Sdim// Run platform-specific leak handlers. 238321369Sdimvoid HandleLeaks(); 239321369Sdim 240251034Sed// Wrapper for chunk metadata operations. 241251034Sedclass LsanMetadata { 242251034Sed public: 243274201Sdim // Constructor accepts address of user-visible chunk. 244274201Sdim explicit LsanMetadata(uptr chunk); 245251034Sed bool allocated() const; 246251034Sed ChunkTag tag() const; 247251034Sed void set_tag(ChunkTag value); 248251034Sed uptr requested_size() const; 249251034Sed u32 stack_trace_id() const; 250251034Sed private: 251251034Sed void *metadata_; 252251034Sed}; 253251034Sed 254251034Sed} // namespace __lsan 255251034Sed 256274201Sdimextern "C" { 257274201SdimSANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE 258327952Sdimconst char *__lsan_default_options(); 259327952Sdim 260327952SdimSANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE 261274201Sdimint __lsan_is_turned_off(); 262274201Sdim 263274201SdimSANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE 264274201Sdimconst char *__lsan_default_suppressions(); 265274201Sdim} // extern "C" 266274201Sdim 267251034Sed#endif // LSAN_COMMON_H 268