1//=-- lsan_common.h -------------------------------------------------------===// 2// 3// This file is distributed under the University of Illinois Open Source 4// License. See LICENSE.TXT for details. 5// 6//===----------------------------------------------------------------------===// 7// 8// This file is a part of LeakSanitizer. 9// Private LSan header. 10// 11//===----------------------------------------------------------------------===// 12 13#ifndef LSAN_COMMON_H 14#define LSAN_COMMON_H 15 16#include "sanitizer_common/sanitizer_allocator.h" 17#include "sanitizer_common/sanitizer_common.h" 18#include "sanitizer_common/sanitizer_internal_defs.h" 19#include "sanitizer_common/sanitizer_platform.h" 20#include "sanitizer_common/sanitizer_stoptheworld.h" 21#include "sanitizer_common/sanitizer_symbolizer.h" 22 23// LeakSanitizer relies on some Glibc's internals (e.g. TLS machinery) on Linux. 24// Also, LSan doesn't like 32 bit architectures 25// because of "small" (4 bytes) pointer size that leads to high false negative 26// ratio on large leaks. But we still want to have it for some 32 bit arches 27// (e.g. x86), see https://github.com/google/sanitizers/issues/403. 28// To enable LeakSanitizer on a new architecture, one needs to implement the 29// internal_clone function as well as (probably) adjust the TLS machinery for 30// the new architecture inside the sanitizer library. 31#if (SANITIZER_LINUX && !SANITIZER_ANDROID || SANITIZER_MAC || SANITIZER_NETBSD) && \ 32 (SANITIZER_WORDSIZE == 64) && \ 33 (defined(__x86_64__) || defined(__mips64) || defined(__aarch64__) || \ 34 defined(__powerpc64__)) 35#define CAN_SANITIZE_LEAKS 1 36#elif defined(__i386__) && \ 37 ((SANITIZER_LINUX && !SANITIZER_ANDROID) || SANITIZER_MAC || SANITIZER_NETBSD) 38#define CAN_SANITIZE_LEAKS 1 39#elif defined(__arm__) && \ 40 ((SANITIZER_LINUX && !SANITIZER_ANDROID) || SANITIZER_NETBSD) 41#define CAN_SANITIZE_LEAKS 1 42#elif SANITIZER_NETBSD 43#define CAN_SANITIZE_LEAKS 1 44#else 45#define CAN_SANITIZE_LEAKS 0 46#endif 47 48namespace __sanitizer { 49class FlagParser; 50class ThreadRegistry; 51struct DTLS; 52} 53 54namespace __lsan { 55 56// Chunk tags. 57enum ChunkTag { 58 kDirectlyLeaked = 0, // default 59 kIndirectlyLeaked = 1, 60 kReachable = 2, 61 kIgnored = 3 62}; 63 64const u32 kInvalidTid = (u32) -1; 65 66struct Flags { 67#define LSAN_FLAG(Type, Name, DefaultValue, Description) Type Name; 68#include "lsan_flags.inc" 69#undef LSAN_FLAG 70 71 void SetDefaults(); 72 uptr pointer_alignment() const { 73 return use_unaligned ? 1 : sizeof(uptr); 74 } 75}; 76 77extern Flags lsan_flags; 78inline Flags *flags() { return &lsan_flags; } 79void RegisterLsanFlags(FlagParser *parser, Flags *f); 80 81struct Leak { 82 u32 id; 83 uptr hit_count; 84 uptr total_size; 85 u32 stack_trace_id; 86 bool is_directly_leaked; 87 bool is_suppressed; 88}; 89 90struct LeakedObject { 91 u32 leak_id; 92 uptr addr; 93 uptr size; 94}; 95 96// Aggregates leaks by stack trace prefix. 97class LeakReport { 98 public: 99 LeakReport() {} 100 void AddLeakedChunk(uptr chunk, u32 stack_trace_id, uptr leaked_size, 101 ChunkTag tag); 102 void ReportTopLeaks(uptr max_leaks); 103 void PrintSummary(); 104 void ApplySuppressions(); 105 uptr UnsuppressedLeakCount(); 106 107 private: 108 void PrintReportForLeak(uptr index); 109 void PrintLeakedObjectsForLeak(uptr index); 110 111 u32 next_id_ = 0; 112 InternalMmapVector<Leak> leaks_; 113 InternalMmapVector<LeakedObject> leaked_objects_; 114}; 115 116typedef InternalMmapVector<uptr> Frontier; 117 118// Platform-specific functions. 119void InitializePlatformSpecificModules(); 120void ProcessGlobalRegions(Frontier *frontier); 121void ProcessPlatformSpecificAllocations(Frontier *frontier); 122 123struct RootRegion { 124 uptr begin; 125 uptr size; 126}; 127 128InternalMmapVector<RootRegion> const *GetRootRegions(); 129void ScanRootRegion(Frontier *frontier, RootRegion const ®ion, 130 uptr region_begin, uptr region_end, bool is_readable); 131// Run stoptheworld while holding any platform-specific locks. 132void DoStopTheWorld(StopTheWorldCallback callback, void* argument); 133 134void ScanRangeForPointers(uptr begin, uptr end, 135 Frontier *frontier, 136 const char *region_type, ChunkTag tag); 137void ScanGlobalRange(uptr begin, uptr end, Frontier *frontier); 138 139enum IgnoreObjectResult { 140 kIgnoreObjectSuccess, 141 kIgnoreObjectAlreadyIgnored, 142 kIgnoreObjectInvalid 143}; 144 145// Functions called from the parent tool. 146const char *MaybeCallLsanDefaultOptions(); 147void InitCommonLsan(); 148void DoLeakCheck(); 149void DoRecoverableLeakCheckVoid(); 150void DisableCounterUnderflow(); 151bool DisabledInThisThread(); 152 153// Used to implement __lsan::ScopedDisabler. 154void DisableInThisThread(); 155void EnableInThisThread(); 156// Can be used to ignore memory allocated by an intercepted 157// function. 158struct ScopedInterceptorDisabler { 159 ScopedInterceptorDisabler() { DisableInThisThread(); } 160 ~ScopedInterceptorDisabler() { EnableInThisThread(); } 161}; 162 163// According to Itanium C++ ABI array cookie is a one word containing 164// size of allocated array. 165static inline bool IsItaniumABIArrayCookie(uptr chunk_beg, uptr chunk_size, 166 uptr addr) { 167 return chunk_size == sizeof(uptr) && chunk_beg + chunk_size == addr && 168 *reinterpret_cast<uptr *>(chunk_beg) == 0; 169} 170 171// According to ARM C++ ABI array cookie consists of two words: 172// struct array_cookie { 173// std::size_t element_size; // element_size != 0 174// std::size_t element_count; 175// }; 176static inline bool IsARMABIArrayCookie(uptr chunk_beg, uptr chunk_size, 177 uptr addr) { 178 return chunk_size == 2 * sizeof(uptr) && chunk_beg + chunk_size == addr && 179 *reinterpret_cast<uptr *>(chunk_beg + sizeof(uptr)) == 0; 180} 181 182// Special case for "new T[0]" where T is a type with DTOR. 183// new T[0] will allocate a cookie (one or two words) for the array size (0) 184// and store a pointer to the end of allocated chunk. The actual cookie layout 185// varies between platforms according to their C++ ABI implementation. 186inline bool IsSpecialCaseOfOperatorNew0(uptr chunk_beg, uptr chunk_size, 187 uptr addr) { 188#if defined(__arm__) 189 return IsARMABIArrayCookie(chunk_beg, chunk_size, addr); 190#else 191 return IsItaniumABIArrayCookie(chunk_beg, chunk_size, addr); 192#endif 193} 194 195// The following must be implemented in the parent tool. 196 197void ForEachChunk(ForEachChunkCallback callback, void *arg); 198// Returns the address range occupied by the global allocator object. 199void GetAllocatorGlobalRange(uptr *begin, uptr *end); 200// Wrappers for allocator's ForceLock()/ForceUnlock(). 201void LockAllocator(); 202void UnlockAllocator(); 203// Returns true if [addr, addr + sizeof(void *)) is poisoned. 204bool WordIsPoisoned(uptr addr); 205// Wrappers for ThreadRegistry access. 206void LockThreadRegistry(); 207void UnlockThreadRegistry(); 208ThreadRegistry *GetThreadRegistryLocked(); 209bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end, 210 uptr *tls_begin, uptr *tls_end, uptr *cache_begin, 211 uptr *cache_end, DTLS **dtls); 212void ForEachExtraStackRange(tid_t os_id, RangeIteratorCallback callback, 213 void *arg); 214// If called from the main thread, updates the main thread's TID in the thread 215// registry. We need this to handle processes that fork() without a subsequent 216// exec(), which invalidates the recorded TID. To update it, we must call 217// gettid() from the main thread. Our solution is to call this function before 218// leak checking and also before every call to pthread_create() (to handle cases 219// where leak checking is initiated from a non-main thread). 220void EnsureMainThreadIDIsCorrect(); 221// If p points into a chunk that has been allocated to the user, returns its 222// user-visible address. Otherwise, returns 0. 223uptr PointsIntoChunk(void *p); 224// Returns address of user-visible chunk contained in this allocator chunk. 225uptr GetUserBegin(uptr chunk); 226// Helper for __lsan_ignore_object(). 227IgnoreObjectResult IgnoreObjectLocked(const void *p); 228 229// Return the linker module, if valid for the platform. 230LoadedModule *GetLinker(); 231 232// Return true if LSan has finished leak checking and reported leaks. 233bool HasReportedLeaks(); 234 235// Run platform-specific leak handlers. 236void HandleLeaks(); 237 238// Wrapper for chunk metadata operations. 239class LsanMetadata { 240 public: 241 // Constructor accepts address of user-visible chunk. 242 explicit LsanMetadata(uptr chunk); 243 bool allocated() const; 244 ChunkTag tag() const; 245 void set_tag(ChunkTag value); 246 uptr requested_size() const; 247 u32 stack_trace_id() const; 248 private: 249 void *metadata_; 250}; 251 252} // namespace __lsan 253 254extern "C" { 255SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE 256const char *__lsan_default_options(); 257 258SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE 259int __lsan_is_turned_off(); 260 261SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE 262const char *__lsan_default_suppressions(); 263} // extern "C" 264 265#endif // LSAN_COMMON_H 266