| 1 | //=-- lsan_common.h -------------------------------------------------------===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | // |
| 9 | // This file is a part of LeakSanitizer. |
| 10 | // Private LSan header. |
| 11 | // |
| 12 | //===----------------------------------------------------------------------===// |
| 13 | |
| 14 | #ifndef LSAN_COMMON_H |
| 15 | #define LSAN_COMMON_H |
| 16 | |
| 17 | #include "sanitizer_common/sanitizer_allocator.h" |
| 18 | #include "sanitizer_common/sanitizer_common.h" |
| 19 | #include "sanitizer_common/sanitizer_internal_defs.h" |
| 20 | #include "sanitizer_common/sanitizer_platform.h" |
| 21 | #include "sanitizer_common/sanitizer_range.h" |
| 22 | #include "sanitizer_common/sanitizer_stackdepot.h" |
| 23 | #include "sanitizer_common/sanitizer_stoptheworld.h" |
| 24 | #include "sanitizer_common/sanitizer_symbolizer.h" |
| 25 | #include "sanitizer_common/sanitizer_thread_registry.h" |
| 26 | |
| 27 | // LeakSanitizer relies on some Glibc's internals (e.g. TLS machinery) on Linux. |
| 28 | // Also, LSan doesn't like 32 bit architectures |
| 29 | // because of "small" (4 bytes) pointer size that leads to high false negative |
| 30 | // ratio on large leaks. But we still want to have it for some 32 bit arches |
| 31 | // (e.g. x86), see https://github.com/google/sanitizers/issues/403. |
| 32 | // To enable LeakSanitizer on a new architecture, one needs to implement the |
| 33 | // internal_clone function as well as (probably) adjust the TLS machinery for |
| 34 | // the new architecture inside the sanitizer library. |
| 35 | // Exclude leak-detection on arm32 for Android because `__aeabi_read_tp` |
| 36 | // is missing. This caused a link error. |
| 37 | #if SANITIZER_ANDROID && (__ANDROID_API__ < 28 || defined(__arm__)) |
| 38 | # define CAN_SANITIZE_LEAKS 0 |
| 39 | #elif (SANITIZER_LINUX || SANITIZER_APPLE) && (SANITIZER_WORDSIZE == 64) && \ |
| 40 | (defined(__x86_64__) || defined(__mips64) || defined(__aarch64__) || \ |
| 41 | defined(__powerpc64__) || defined(__s390x__)) |
| 42 | # define CAN_SANITIZE_LEAKS 1 |
| 43 | #elif defined(__i386__) && (SANITIZER_LINUX || SANITIZER_APPLE) |
| 44 | # define CAN_SANITIZE_LEAKS 1 |
| 45 | #elif defined(__arm__) && SANITIZER_LINUX |
| 46 | # define CAN_SANITIZE_LEAKS 1 |
| 47 | #elif SANITIZER_LOONGARCH64 && SANITIZER_LINUX |
| 48 | # define CAN_SANITIZE_LEAKS 1 |
| 49 | #elif SANITIZER_RISCV64 && SANITIZER_LINUX |
| 50 | # define CAN_SANITIZE_LEAKS 1 |
| 51 | #elif SANITIZER_NETBSD || SANITIZER_FUCHSIA |
| 52 | # define CAN_SANITIZE_LEAKS 1 |
| 53 | #else |
| 54 | # define CAN_SANITIZE_LEAKS 0 |
| 55 | #endif |
| 56 | |
| 57 | namespace __sanitizer { |
| 58 | class FlagParser; |
| 59 | class ThreadRegistry; |
| 60 | class ThreadContextBase; |
| 61 | struct DTLS; |
| 62 | } |
| 63 | |
| 64 | // This section defines function and class prototypes which must be implemented |
| 65 | // by the parent tool linking in LSan. There are implementations provided by the |
| 66 | // LSan library which will be linked in when LSan is used as a standalone tool. |
| 67 | namespace __lsan { |
| 68 | |
| 69 | // Chunk tags. |
| 70 | enum ChunkTag { |
| 71 | kDirectlyLeaked = 0, // default |
| 72 | kIndirectlyLeaked = 1, |
| 73 | kReachable = 2, |
| 74 | kIgnored = 3 |
| 75 | }; |
| 76 | |
| 77 | enum IgnoreObjectResult { |
| 78 | kIgnoreObjectSuccess, |
| 79 | kIgnoreObjectAlreadyIgnored, |
| 80 | kIgnoreObjectInvalid |
| 81 | }; |
| 82 | |
| 83 | //// -------------------------------------------------------------------------- |
| 84 | //// Poisoning prototypes. |
| 85 | //// -------------------------------------------------------------------------- |
| 86 | |
| 87 | // Returns true if [addr, addr + sizeof(void *)) is poisoned. |
| 88 | bool WordIsPoisoned(uptr addr); |
| 89 | |
| 90 | //// -------------------------------------------------------------------------- |
| 91 | //// Thread prototypes. |
| 92 | //// -------------------------------------------------------------------------- |
| 93 | |
| 94 | // Wrappers for ThreadRegistry access. |
| 95 | void LockThreads() SANITIZER_NO_THREAD_SAFETY_ANALYSIS; |
| 96 | void UnlockThreads() SANITIZER_NO_THREAD_SAFETY_ANALYSIS; |
| 97 | // If called from the main thread, updates the main thread's TID in the thread |
| 98 | // registry. We need this to handle processes that fork() without a subsequent |
| 99 | // exec(), which invalidates the recorded TID. To update it, we must call |
| 100 | // gettid() from the main thread. Our solution is to call this function before |
| 101 | // leak checking and also before every call to pthread_create() (to handle cases |
| 102 | // where leak checking is initiated from a non-main thread). |
| 103 | void EnsureMainThreadIDIsCorrect(); |
| 104 | |
| 105 | bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end, |
| 106 | uptr *tls_begin, uptr *tls_end, uptr *cache_begin, |
| 107 | uptr *cache_end, DTLS **dtls); |
| 108 | void GetAllThreadAllocatorCachesLocked(InternalMmapVector<uptr> *caches); |
| 109 | void (InternalMmapVector<Range> *ranges); |
| 110 | void (tid_t os_id, |
| 111 | InternalMmapVector<Range> *ranges); |
| 112 | void GetAdditionalThreadContextPtrsLocked(InternalMmapVector<uptr> *ptrs); |
| 113 | void GetRunningThreadsLocked(InternalMmapVector<tid_t> *threads); |
| 114 | void PrintThreads(); |
| 115 | |
| 116 | //// -------------------------------------------------------------------------- |
| 117 | //// Allocator prototypes. |
| 118 | //// -------------------------------------------------------------------------- |
| 119 | |
| 120 | // Wrappers for allocator's ForceLock()/ForceUnlock(). |
| 121 | void LockAllocator(); |
| 122 | void UnlockAllocator(); |
| 123 | |
| 124 | // Lock/unlock global mutext. |
| 125 | void LockGlobal(); |
| 126 | void UnlockGlobal(); |
| 127 | |
| 128 | // Returns the address range occupied by the global allocator object. |
| 129 | void GetAllocatorGlobalRange(uptr *begin, uptr *end); |
| 130 | // If p points into a chunk that has been allocated to the user, returns its |
| 131 | // user-visible address. Otherwise, returns 0. |
| 132 | uptr PointsIntoChunk(void *p); |
| 133 | // Returns address of user-visible chunk contained in this allocator chunk. |
| 134 | uptr GetUserBegin(uptr chunk); |
| 135 | // Returns user-visible address for chunk. If memory tagging is used this |
| 136 | // function will return the tagged address. |
| 137 | uptr GetUserAddr(uptr chunk); |
| 138 | |
| 139 | // Wrapper for chunk metadata operations. |
| 140 | class LsanMetadata { |
| 141 | public: |
| 142 | // Constructor accepts address of user-visible chunk. |
| 143 | explicit LsanMetadata(uptr chunk); |
| 144 | bool allocated() const; |
| 145 | ChunkTag tag() const; |
| 146 | void set_tag(ChunkTag value); |
| 147 | uptr requested_size() const; |
| 148 | u32 stack_trace_id() const; |
| 149 | |
| 150 | private: |
| 151 | void *metadata_; |
| 152 | }; |
| 153 | |
| 154 | // Iterate over all existing chunks. Allocator must be locked. |
| 155 | void ForEachChunk(ForEachChunkCallback callback, void *arg); |
| 156 | |
| 157 | // Helper for __lsan_ignore_object(). |
| 158 | IgnoreObjectResult IgnoreObject(const void *p); |
| 159 | |
| 160 | // The rest of the LSan interface which is implemented by library. |
| 161 | |
| 162 | struct ScopedStopTheWorldLock { |
| 163 | ScopedStopTheWorldLock() { |
| 164 | LockThreads(); |
| 165 | LockAllocator(); |
| 166 | } |
| 167 | |
| 168 | ~ScopedStopTheWorldLock() { |
| 169 | UnlockAllocator(); |
| 170 | UnlockThreads(); |
| 171 | } |
| 172 | |
| 173 | ScopedStopTheWorldLock &operator=(const ScopedStopTheWorldLock &) = delete; |
| 174 | ScopedStopTheWorldLock(const ScopedStopTheWorldLock &) = delete; |
| 175 | }; |
| 176 | |
| 177 | struct Flags { |
| 178 | #define LSAN_FLAG(Type, Name, DefaultValue, Description) Type Name; |
| 179 | #include "lsan_flags.inc" |
| 180 | #undef LSAN_FLAG |
| 181 | |
| 182 | void SetDefaults(); |
| 183 | uptr pointer_alignment() const { |
| 184 | return use_unaligned ? 1 : sizeof(uptr); |
| 185 | } |
| 186 | }; |
| 187 | |
| 188 | extern Flags lsan_flags; |
| 189 | inline Flags *flags() { return &lsan_flags; } |
| 190 | void RegisterLsanFlags(FlagParser *parser, Flags *f); |
| 191 | |
| 192 | struct LeakedChunk { |
| 193 | uptr chunk; |
| 194 | u32 stack_trace_id; |
| 195 | uptr leaked_size; |
| 196 | ChunkTag tag; |
| 197 | }; |
| 198 | |
| 199 | using LeakedChunks = InternalMmapVector<LeakedChunk>; |
| 200 | |
| 201 | struct Leak { |
| 202 | u32 id; |
| 203 | uptr hit_count; |
| 204 | uptr total_size; |
| 205 | u32 stack_trace_id; |
| 206 | bool is_directly_leaked; |
| 207 | bool is_suppressed; |
| 208 | }; |
| 209 | |
| 210 | struct LeakedObject { |
| 211 | u32 leak_id; |
| 212 | uptr addr; |
| 213 | uptr size; |
| 214 | }; |
| 215 | |
| 216 | // Aggregates leaks by stack trace prefix. |
| 217 | class LeakReport { |
| 218 | public: |
| 219 | LeakReport() {} |
| 220 | void AddLeakedChunks(const LeakedChunks &chunks); |
| 221 | void ReportTopLeaks(uptr max_leaks); |
| 222 | void PrintSummary(); |
| 223 | uptr ApplySuppressions(); |
| 224 | uptr UnsuppressedLeakCount(); |
| 225 | uptr IndirectUnsuppressedLeakCount(); |
| 226 | |
| 227 | private: |
| 228 | void PrintReportForLeak(uptr index); |
| 229 | void PrintLeakedObjectsForLeak(uptr index); |
| 230 | |
| 231 | u32 next_id_ = 0; |
| 232 | InternalMmapVector<Leak> leaks_; |
| 233 | InternalMmapVector<LeakedObject> leaked_objects_; |
| 234 | }; |
| 235 | |
| 236 | typedef InternalMmapVector<uptr> Frontier; |
| 237 | |
| 238 | // Platform-specific functions. |
| 239 | void InitializePlatformSpecificModules(); |
| 240 | void ProcessGlobalRegions(Frontier *frontier); |
| 241 | void ProcessPlatformSpecificAllocations(Frontier *frontier); |
| 242 | |
| 243 | // LockStuffAndStopTheWorld can start to use Scan* calls to collect into |
| 244 | // this Frontier vector before the StopTheWorldCallback actually runs. |
| 245 | // This is used when the OS has a unified callback API for suspending |
| 246 | // threads and enumerating roots. |
| 247 | struct CheckForLeaksParam { |
| 248 | Frontier frontier; |
| 249 | LeakedChunks leaks; |
| 250 | tid_t caller_tid; |
| 251 | uptr caller_sp; |
| 252 | bool success = false; |
| 253 | }; |
| 254 | |
| 255 | using Region = Range; |
| 256 | |
| 257 | bool HasRootRegions(); |
| 258 | void ScanRootRegions(Frontier *frontier, |
| 259 | const InternalMmapVectorNoCtor<Region> ®ion); |
| 260 | // Run stoptheworld while holding any platform-specific locks, as well as the |
| 261 | // allocator and thread registry locks. |
| 262 | void LockStuffAndStopTheWorld(StopTheWorldCallback callback, |
| 263 | CheckForLeaksParam* argument); |
| 264 | |
| 265 | void ScanRangeForPointers(uptr begin, uptr end, |
| 266 | Frontier *frontier, |
| 267 | const char *region_type, ChunkTag tag); |
| 268 | void ScanGlobalRange(uptr begin, uptr end, Frontier *frontier); |
| 269 | void (const InternalMmapVector<Range> &ranges, |
| 270 | Frontier *frontier); |
| 271 | |
| 272 | // Functions called from the parent tool. |
| 273 | const char *MaybeCallLsanDefaultOptions(); |
| 274 | void InitCommonLsan(); |
| 275 | void DoLeakCheck(); |
| 276 | void DoRecoverableLeakCheckVoid(); |
| 277 | void DisableCounterUnderflow(); |
| 278 | bool DisabledInThisThread(); |
| 279 | |
| 280 | // Used to implement __lsan::ScopedDisabler. |
| 281 | void DisableInThisThread(); |
| 282 | void EnableInThisThread(); |
| 283 | // Can be used to ignore memory allocated by an intercepted |
| 284 | // function. |
| 285 | struct ScopedInterceptorDisabler { |
| 286 | ScopedInterceptorDisabler() { DisableInThisThread(); } |
| 287 | ~ScopedInterceptorDisabler() { EnableInThisThread(); } |
| 288 | }; |
| 289 | |
| 290 | // According to Itanium C++ ABI array cookie is a one word containing |
| 291 | // size of allocated array. |
| 292 | static inline bool IsItaniumABIArrayCookie(uptr chunk_beg, uptr chunk_size, |
| 293 | uptr addr) { |
| 294 | return chunk_size == sizeof(uptr) && chunk_beg + chunk_size == addr && |
| 295 | *reinterpret_cast<uptr *>(chunk_beg) == 0; |
| 296 | } |
| 297 | |
| 298 | // According to ARM C++ ABI array cookie consists of two words: |
| 299 | // struct array_cookie { |
| 300 | // std::size_t element_size; // element_size != 0 |
| 301 | // std::size_t element_count; |
| 302 | // }; |
| 303 | static inline bool IsARMABIArrayCookie(uptr chunk_beg, uptr chunk_size, |
| 304 | uptr addr) { |
| 305 | return chunk_size == 2 * sizeof(uptr) && chunk_beg + chunk_size == addr && |
| 306 | *reinterpret_cast<uptr *>(chunk_beg + sizeof(uptr)) == 0; |
| 307 | } |
| 308 | |
| 309 | // Special case for "new T[0]" where T is a type with DTOR. |
| 310 | // new T[0] will allocate a cookie (one or two words) for the array size (0) |
| 311 | // and store a pointer to the end of allocated chunk. The actual cookie layout |
| 312 | // varies between platforms according to their C++ ABI implementation. |
| 313 | inline bool IsSpecialCaseOfOperatorNew0(uptr chunk_beg, uptr chunk_size, |
| 314 | uptr addr) { |
| 315 | #if defined(__arm__) |
| 316 | return IsARMABIArrayCookie(chunk_beg, chunk_size, addr); |
| 317 | #else |
| 318 | return IsItaniumABIArrayCookie(chunk_beg, chunk_size, addr); |
| 319 | #endif |
| 320 | } |
| 321 | |
| 322 | // Return the linker module, if valid for the platform. |
| 323 | LoadedModule *GetLinker(); |
| 324 | |
| 325 | // Return true if LSan has finished leak checking and reported leaks. |
| 326 | bool HasReportedLeaks(); |
| 327 | |
| 328 | // Run platform-specific leak handlers. |
| 329 | void HandleLeaks(); |
| 330 | |
| 331 | } // namespace __lsan |
| 332 | |
| 333 | extern "C" { |
| 334 | SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE |
| 335 | const char *__lsan_default_options(); |
| 336 | |
| 337 | SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE |
| 338 | int __lsan_is_turned_off(); |
| 339 | |
| 340 | SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE |
| 341 | const char *__lsan_default_suppressions(); |
| 342 | |
| 343 | SANITIZER_INTERFACE_ATTRIBUTE |
| 344 | void __lsan_register_root_region(const void *p, __lsan::uptr size); |
| 345 | |
| 346 | SANITIZER_INTERFACE_ATTRIBUTE |
| 347 | void __lsan_unregister_root_region(const void *p, __lsan::uptr size); |
| 348 | |
| 349 | } // extern "C" |
| 350 | |
| 351 | #endif // LSAN_COMMON_H |
| 352 | |