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 #if (SANITIZER_LINUX && !SANITIZER_ANDROID) && (SANITIZER_WORDSIZE == 64) \ 24 && (defined(__x86_64__) || defined(__mips64) || defined(__aarch64__)) 25 #define CAN_SANITIZE_LEAKS 1 26 #else 27 #define CAN_SANITIZE_LEAKS 0 28 #endif 29 30 namespace __sanitizer { 31 class FlagParser; 32 } 33 34 namespace __lsan { 35 36 // Chunk tags. 37 enum ChunkTag { 38 kDirectlyLeaked = 0, // default 39 kIndirectlyLeaked = 1, 40 kReachable = 2, 41 kIgnored = 3 42 }; 43 44 struct Flags { 45 #define LSAN_FLAG(Type, Name, DefaultValue, Description) Type Name; 46 #include "lsan_flags.inc" 47 #undef LSAN_FLAG 48 49 void SetDefaults(); 50 uptr pointer_alignment() const { 51 return use_unaligned ? 1 : sizeof(uptr); 52 } 53 }; 54 55 extern Flags lsan_flags; 56 inline Flags *flags() { return &lsan_flags; } 57 void RegisterLsanFlags(FlagParser *parser, Flags *f); 58 59 struct Leak { 60 u32 id; 61 uptr hit_count; 62 uptr total_size; 63 u32 stack_trace_id; 64 bool is_directly_leaked; 65 bool is_suppressed; 66 }; 67 68 struct LeakedObject { 69 u32 leak_id; 70 uptr addr; 71 uptr size; 72 }; 73 74 // Aggregates leaks by stack trace prefix. 75 class LeakReport { 76 public: 77 LeakReport() : next_id_(0), leaks_(1), leaked_objects_(1) {} 78 void AddLeakedChunk(uptr chunk, u32 stack_trace_id, uptr leaked_size, 79 ChunkTag tag); 80 void ReportTopLeaks(uptr max_leaks); 81 void PrintSummary(); 82 void ApplySuppressions(); 83 uptr UnsuppressedLeakCount(); 84 85 86 private: 87 void PrintReportForLeak(uptr index); 88 void PrintLeakedObjectsForLeak(uptr index); 89 90 u32 next_id_; 91 InternalMmapVector<Leak> leaks_; 92 InternalMmapVector<LeakedObject> leaked_objects_; 93 }; 94 95 typedef InternalMmapVector<uptr> Frontier; 96 97 // Platform-specific functions. 98 void InitializePlatformSpecificModules(); 99 void ProcessGlobalRegions(Frontier *frontier); 100 void ProcessPlatformSpecificAllocations(Frontier *frontier); 101 // Run stoptheworld while holding any platform-specific locks. 102 void DoStopTheWorld(StopTheWorldCallback callback, void* argument); 103 104 void ScanRangeForPointers(uptr begin, uptr end, 105 Frontier *frontier, 106 const char *region_type, ChunkTag tag); 107 108 enum IgnoreObjectResult { 109 kIgnoreObjectSuccess, 110 kIgnoreObjectAlreadyIgnored, 111 kIgnoreObjectInvalid 112 }; 113 114 // Functions called from the parent tool. 115 void InitCommonLsan(); 116 void DoLeakCheck(); 117 bool DisabledInThisThread(); 118 119 // Special case for "new T[0]" where T is a type with DTOR. 120 // new T[0] will allocate one word for the array size (0) and store a pointer 121 // to the end of allocated chunk. 122 inline bool IsSpecialCaseOfOperatorNew0(uptr chunk_beg, uptr chunk_size, 123 uptr addr) { 124 return chunk_size == sizeof(uptr) && chunk_beg + chunk_size == addr && 125 *reinterpret_cast<uptr *>(chunk_beg) == 0; 126 } 127 128 // The following must be implemented in the parent tool. 129 130 void ForEachChunk(ForEachChunkCallback callback, void *arg); 131 // Returns the address range occupied by the global allocator object. 132 void GetAllocatorGlobalRange(uptr *begin, uptr *end); 133 // Wrappers for allocator's ForceLock()/ForceUnlock(). 134 void LockAllocator(); 135 void UnlockAllocator(); 136 // Returns true if [addr, addr + sizeof(void *)) is poisoned. 137 bool WordIsPoisoned(uptr addr); 138 // Wrappers for ThreadRegistry access. 139 void LockThreadRegistry(); 140 void UnlockThreadRegistry(); 141 bool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end, 142 uptr *tls_begin, uptr *tls_end, 143 uptr *cache_begin, uptr *cache_end); 144 void ForEachExtraStackRange(uptr os_id, RangeIteratorCallback callback, 145 void *arg); 146 // If called from the main thread, updates the main thread's TID in the thread 147 // registry. We need this to handle processes that fork() without a subsequent 148 // exec(), which invalidates the recorded TID. To update it, we must call 149 // gettid() from the main thread. Our solution is to call this function before 150 // leak checking and also before every call to pthread_create() (to handle cases 151 // where leak checking is initiated from a non-main thread). 152 void EnsureMainThreadIDIsCorrect(); 153 // If p points into a chunk that has been allocated to the user, returns its 154 // user-visible address. Otherwise, returns 0. 155 uptr PointsIntoChunk(void *p); 156 // Returns address of user-visible chunk contained in this allocator chunk. 157 uptr GetUserBegin(uptr chunk); 158 // Helper for __lsan_ignore_object(). 159 IgnoreObjectResult IgnoreObjectLocked(const void *p); 160 // Wrapper for chunk metadata operations. 161 class LsanMetadata { 162 public: 163 // Constructor accepts address of user-visible chunk. 164 explicit LsanMetadata(uptr chunk); 165 bool allocated() const; 166 ChunkTag tag() const; 167 void set_tag(ChunkTag value); 168 uptr requested_size() const; 169 u32 stack_trace_id() const; 170 private: 171 void *metadata_; 172 }; 173 174 } // namespace __lsan 175 176 extern "C" { 177 SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE 178 int __lsan_is_turned_off(); 179 180 SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE 181 const char *__lsan_default_suppressions(); 182 } // extern "C" 183 184 #endif // LSAN_COMMON_H 185