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