msan_report.cc revision 5d71de26cedae3dafc17449fe0182045c0bd20e8
1//===-- msan_report.cc ----------------------------------------------------===//
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 MemorySanitizer.
11//
12// Error reporting.
13//===----------------------------------------------------------------------===//
14
15#include "msan.h"
16#include "msan_chained_origin_depot.h"
17#include "msan_origin.h"
18#include "sanitizer_common/sanitizer_allocator_internal.h"
19#include "sanitizer_common/sanitizer_common.h"
20#include "sanitizer_common/sanitizer_flags.h"
21#include "sanitizer_common/sanitizer_mutex.h"
22#include "sanitizer_common/sanitizer_report_decorator.h"
23#include "sanitizer_common/sanitizer_stackdepot.h"
24#include "sanitizer_common/sanitizer_symbolizer.h"
25
26using namespace __sanitizer;
27
28namespace __msan {
29
30class Decorator: public __sanitizer::SanitizerCommonDecorator {
31 public:
32  Decorator() : SanitizerCommonDecorator() { }
33  const char *Warning()    { return Red(); }
34  const char *Origin()     { return Magenta(); }
35  const char *Name()   { return Green(); }
36  const char *End()    { return Default(); }
37};
38
39static void DescribeStackOrigin(const char *so, uptr pc) {
40  Decorator d;
41  char *s = internal_strdup(so);
42  char *sep = internal_strchr(s, '@');
43  CHECK(sep);
44  *sep = '\0';
45  Printf("%s", d.Origin());
46  Printf(
47      "  %sUninitialized value was created by an allocation of '%s%s%s'"
48      " in the stack frame of function '%s%s%s'%s\n",
49      d.Origin(), d.Name(), s, d.Origin(), d.Name(),
50      Symbolizer::Get()->Demangle(sep + 1), d.Origin(), d.End());
51  InternalFree(s);
52
53  if (pc) {
54    // For some reason function address in LLVM IR is 1 less then the address
55    // of the first instruction.
56    pc += 1;
57    StackTrace::PrintStack(&pc, 1);
58  }
59}
60
61static void DescribeOrigin(u32 id) {
62  VPrintf(1, "  raw origin id: %d\n", id);
63  Decorator d;
64  while (true) {
65    Origin o(id);
66    if (!o.isValid()) {
67      Printf("  %sinvalid origin id(%d)%s\n", d.Warning(), id, d.End());
68      break;
69    }
70    u32 prev_id;
71    u32 stack_id = ChainedOriginDepotGet(o.id(), &prev_id);
72    Origin prev_o(prev_id);
73
74    if (prev_o.isStackRoot()) {
75      uptr pc;
76      const char *so = GetStackOriginDescr(stack_id, &pc);
77      DescribeStackOrigin(so, pc);
78      break;
79    } else if (prev_o.isHeapRoot()) {
80      uptr size = 0;
81      const uptr *trace = StackDepotGet(stack_id, &size);
82      Printf("  %sUninitialized value was created by a heap allocation%s\n",
83             d.Origin(), d.End());
84      StackTrace::PrintStack(trace, size);
85      break;
86    } else {
87      // chained origin
88      uptr size = 0;
89      const uptr *trace = StackDepotGet(stack_id, &size);
90      // FIXME: copied? modified? passed through? observed?
91      Printf("  %sUninitialized value was stored to memory at%s\n", d.Origin(),
92             d.End());
93      StackTrace::PrintStack(trace, size);
94      id = prev_id;
95    }
96  }
97}
98
99void ReportUMR(StackTrace *stack, u32 origin) {
100  if (!__msan::flags()->report_umrs) return;
101
102  SpinMutexLock l(&CommonSanitizerReportMutex);
103
104  Decorator d;
105  Printf("%s", d.Warning());
106  Report(" WARNING: MemorySanitizer: use-of-uninitialized-value\n");
107  Printf("%s", d.End());
108  stack->Print();
109  if (origin) {
110    DescribeOrigin(origin);
111  }
112  ReportErrorSummary("use-of-uninitialized-value", stack);
113}
114
115void ReportExpectedUMRNotFound(StackTrace *stack) {
116  SpinMutexLock l(&CommonSanitizerReportMutex);
117
118  Printf(" WARNING: Expected use of uninitialized value not found\n");
119  stack->Print();
120}
121
122void ReportStats() {
123  SpinMutexLock l(&CommonSanitizerReportMutex);
124
125  if (__msan_get_track_origins() > 0) {
126    StackDepotStats *stack_depot_stats = StackDepotGetStats();
127    // FIXME: we want this at normal exit, too!
128    // FIXME: but only with verbosity=1 or something
129    Printf("Unique heap origins: %zu\n", stack_depot_stats->n_uniq_ids);
130    Printf("Stack depot allocated bytes: %zu\n", stack_depot_stats->allocated);
131
132    StackDepotStats *chained_origin_depot_stats = ChainedOriginDepotGetStats();
133    Printf("Unique origin histories: %zu\n",
134           chained_origin_depot_stats->n_uniq_ids);
135    Printf("History depot allocated bytes: %zu\n",
136           chained_origin_depot_stats->allocated);
137  }
138}
139
140void ReportAtExitStatistics() {
141  SpinMutexLock l(&CommonSanitizerReportMutex);
142
143  if (msan_report_count > 0) {
144    Decorator d;
145    Printf("%s", d.Warning());
146    Printf("MemorySanitizer: %d warnings reported.\n", msan_report_count);
147    Printf("%s", d.End());
148  }
149}
150
151class OriginSet {
152 public:
153  OriginSet() : next_id_(0) {}
154  int insert(u32 o) {
155    // Scan from the end for better locality.
156    for (int i = next_id_ - 1; i >= 0; --i)
157      if (origins_[i] == o) return i;
158    if (next_id_ == kMaxSize_) return OVERFLOW;
159    int id = next_id_++;
160    origins_[id] = o;
161    return id;
162  }
163  int size() { return next_id_; }
164  u32 get(int id) { return origins_[id]; }
165  static char asChar(int id) {
166    switch (id) {
167      case MISSING:
168        return '.';
169      case OVERFLOW:
170        return '*';
171      default:
172        return 'A' + id;
173    }
174  }
175  static const int OVERFLOW = -1;
176  static const int MISSING = -2;
177
178 private:
179  static const int kMaxSize_ = 'Z' - 'A' + 1;
180  u32 origins_[kMaxSize_];
181  int next_id_;
182};
183
184void DescribeMemoryRange(const void *x, uptr size) {
185  // Real limits.
186  uptr start = MEM_TO_SHADOW(x);
187  uptr end = start + size;
188  // Scan limits: align start down to 4; align size up to 16.
189  uptr s = start & ~3UL;
190  size = end - s;
191  size = (size + 15) & ~15UL;
192  uptr e = s + size;
193
194  // Single letter names to origin id mapping.
195  OriginSet origin_set;
196
197  uptr pos = 0;  // Offset from aligned start.
198  bool with_origins = __msan_get_track_origins();
199  // True if there is at least 1 poisoned bit in the last 4-byte group.
200  bool last_quad_poisoned;
201  int origin_ids[4];  // Single letter origin ids for the current line.
202
203  Decorator d;
204  Printf("%s", d.Warning());
205  Printf("Shadow map of [%p, %p), %zu bytes:\n", start, end, end - start);
206  Printf("%s", d.End());
207  while (s < e) {
208    // Line start.
209    if (pos % 16 == 0) {
210      for (int i = 0; i < 4; ++i) origin_ids[i] = -1;
211      Printf("%p:", s);
212    }
213    // Group start.
214    if (pos % 4 == 0) {
215      Printf(" ");
216      last_quad_poisoned = false;
217    }
218    // Print shadow byte.
219    if (s < start || s >= end) {
220      Printf("..");
221    } else {
222      unsigned char v = *(unsigned char *)s;
223      if (v) last_quad_poisoned = true;
224#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
225      Printf("%x%x", v & 0xf, v >> 4);
226#else
227      Printf("%x%x", v >> 4, v & 0xf);
228#endif
229    }
230    // Group end.
231    if (pos % 4 == 3 && with_origins) {
232      int id = OriginSet::MISSING;
233      if (last_quad_poisoned) {
234        u32 o = *(u32 *)SHADOW_TO_ORIGIN(s - 3);
235        id = origin_set.insert(o);
236      }
237      origin_ids[(pos % 16) / 4] = id;
238    }
239    // Line end.
240    if (pos % 16 == 15) {
241      if (with_origins) {
242        Printf("  |");
243        for (int i = 0; i < 4; ++i) {
244          char c = OriginSet::asChar(origin_ids[i]);
245          Printf("%c", c);
246          if (i != 3) Printf(" ");
247        }
248        Printf("|");
249      }
250      Printf("\n");
251    }
252    size--;
253    s++;
254    pos++;
255  }
256
257  Printf("\n");
258
259  for (int i = 0; i < origin_set.size(); ++i) {
260    u32 o = origin_set.get(i);
261    Printf("Origin %c (origin_id %x):\n", OriginSet::asChar(i), o);
262    DescribeOrigin(o);
263  }
264}
265
266void ReportUMRInsideAddressRange(const char *what, const void *start, uptr size,
267                                 uptr offset) {
268  Decorator d;
269  Printf("%s", d.Warning());
270  Printf("%sUninitialized bytes in %s%s%s at offset %zu inside [%p, %zu)%s\n",
271         d.Warning(), d.Name(), what, d.Warning(), offset, start, size,
272         d.End());
273  if (__sanitizer::common_flags()->verbosity > 0)
274    DescribeMemoryRange(start, size);
275}
276
277}  // namespace __msan
278