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