aboutsummaryrefslogtreecommitdiff
path: root/lib/lsan/lsan_common.h
blob: 8cb4b2753cd9b2a19b1141124821c64de300832f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
//=-- lsan_common.h -------------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is a part of LeakSanitizer.
// Private LSan header.
//
//===----------------------------------------------------------------------===//

#ifndef LSAN_COMMON_H
#define LSAN_COMMON_H

#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_internal_defs.h"
#include "sanitizer_common/sanitizer_platform.h"
#include "sanitizer_common/sanitizer_symbolizer.h"

#if SANITIZER_LINUX && defined(__x86_64__)
#define CAN_SANITIZE_LEAKS 1
#else
#define CAN_SANITIZE_LEAKS 0
#endif

namespace __lsan {

// Chunk tags.
enum ChunkTag {
  kDirectlyLeaked = 0,  // default
  kIndirectlyLeaked = 1,
  kReachable = 2
};

struct Flags {
  uptr pointer_alignment() const {
    return use_unaligned ? 1 : sizeof(uptr);
  }

  // Print addresses of leaked blocks after main leak report.
  bool report_blocks;
  // Aggregate two blocks into one leak if this many stack frames match. If
  // zero, the entire stack trace must match.
  int resolution;
  // The number of leaks reported.
  int max_leaks;
  // If nonzero kill the process with this exit code upon finding leaks.
  int exitcode;

  // Flags controlling the root set of reachable memory.
  // Global variables (.data and .bss).
  bool use_globals;
  // Thread stacks.
  bool use_stacks;
  // Thread registers.
  bool use_registers;
  // TLS and thread-specific storage.
  bool use_tls;

  // Consider unaligned pointers valid.
  bool use_unaligned;

  // Debug logging.
  bool log_pointers;
  bool log_threads;
};

extern Flags lsan_flags;
inline Flags *flags() { return &lsan_flags; }

void InitCommonLsan();
// Testing interface. Find leaked chunks and dump their addresses to vector.
void ReportLeaked(InternalVector<void *> *leaked, uptr sources);
// Normal leak check. Find leaks and print a report according to flags.
void DoLeakCheck();

struct Leak {
  uptr hit_count;
  uptr total_size;
  u32 stack_trace_id;
  bool is_directly_leaked;
};

// Aggregates leaks by stack trace prefix.
class LeakReport {
 public:
  LeakReport() : leaks_(1) {}
  void Add(u32 stack_trace_id, uptr leaked_size, ChunkTag tag);
  void PrintLargest(uptr max_leaks);
  void PrintSummary();
  bool IsEmpty() { return leaks_.size() == 0; }
 private:
  InternalVector<Leak> leaks_;
};

// Platform-specific functions.
void InitializePlatformSpecificModules();
void ProcessGlobalRegions(InternalVector<uptr> *frontier);
void ProcessPlatformSpecificAllocations(InternalVector<uptr> *frontier);

void ScanRangeForPointers(uptr begin, uptr end, InternalVector<uptr> *frontier,
                          const char *region_type, ChunkTag tag);

// Callables for iterating over chunks. Those classes are used as template
// parameters in ForEachChunk, so we must expose them here to allow for explicit
// template instantiation.

// Identifies unreachable chunks which must be treated as reachable. Marks them
// as reachable and adds them to the frontier.
class ProcessPlatformSpecificAllocationsCb {
 public:
  explicit ProcessPlatformSpecificAllocationsCb(InternalVector<uptr> *frontier)
      : frontier_(frontier) {}
  void operator()(void *p) const;
 private:
  InternalVector<uptr> *frontier_;
};

// Prints addresses of unreachable chunks.
class PrintLeakedCb {
 public:
  void operator()(void *p) const;
};

// Aggregates unreachable chunks into a LeakReport.
class CollectLeaksCb {
 public:
  explicit CollectLeaksCb(LeakReport *leak_report)
      : leak_report_(leak_report) {}
  void operator()(void *p) const;
 private:
  LeakReport *leak_report_;
};

// Resets each chunk's tag to default (kDirectlyLeaked).
class ClearTagCb {
 public:
  void operator()(void *p) const;
};

// Scans each leaked chunk for pointers to other leaked chunks, and marks each
// of them as indirectly leaked.
class MarkIndirectlyLeakedCb {
 public:
  void operator()(void *p) const;
};

// The following must be implemented in the parent tool.

template<typename Callable> void ForEachChunk(Callable const &callback);
// The address range occupied by the global allocator object.
void GetAllocatorGlobalRange(uptr *begin, uptr *end);
// Wrappers for allocator's ForceLock()/ForceUnlock().
void LockAllocator();
void UnlockAllocator();
// Wrappers for ThreadRegistry access.
void LockThreadRegistry();
void UnlockThreadRegistry();
bool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end,
                           uptr *tls_begin, uptr *tls_end,
                           uptr *cache_begin, uptr *cache_end);
// If p points into a chunk that has been allocated to the user, return its
// user-visible address. Otherwise, return 0.
void *PointsIntoChunk(void *p);
// Return address of user-visible chunk contained in this allocator chunk.
void *GetUserBegin(void *p);
// Wrapper for chunk metadata operations.
class LsanMetadata {
 public:
  // Constructor accepts pointer to user-visible chunk.
  explicit LsanMetadata(void *chunk);
  bool allocated() const;
  ChunkTag tag() const;
  void set_tag(ChunkTag value);
  uptr requested_size() const;
  u32 stack_trace_id() const;
 private:
  void *metadata_;
};

}  // namespace __lsan

#endif  // LSAN_COMMON_H