annotate libsanitizer/lsan/lsan_common.h @ 136:4627f235cf2a

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