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 &region,
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