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