1 //===-- msan_report.cpp ---------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file is a part of MemorySanitizer.
12 //===----------------------------------------------------------------------===//
14 #include "msan_report.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"
28 using namespace __sanitizer
;
32 class Decorator
: public __sanitizer::SanitizerCommonDecorator
{
34 Decorator() : SanitizerCommonDecorator() { }
35 const char *Origin() const { return Magenta(); }
36 const char *Name() const { return Green(); }
39 static void DescribeStackOrigin(const char *so
, uptr pc
) {
41 Printf("%s", d
.Origin());
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());
48 Printf(" %sUninitialized value was created in the stack frame%s\n",
49 d
.Origin(), d
.Default());
53 StackTrace(&pc
, 1).Print();
56 static void DescribeOrigin(u32 id
) {
57 VPrintf(1, " raw origin id: %d\n", id
);
59 Origin o
= Origin::FromRawId(id
);
60 while (o
.isChainedOrigin()) {
62 o
= o
.getNextChainedOrigin(&stack
);
63 Printf(" %sUninitialized value was stored to memory at%s\n", d
.Origin(),
67 if (o
.isStackOrigin()) {
69 const char *so
= GetStackOriginDescr(o
.getStackId(), &pc
);
70 DescribeStackOrigin(so
, pc
);
72 StackTrace stack
= o
.getStackTraceForHeapOrigin();
74 case StackTrace::TAG_ALLOC
:
75 Printf(" %sUninitialized value was created by a heap allocation%s\n",
76 d
.Origin(), d
.Default());
78 case StackTrace::TAG_DEALLOC
:
79 Printf(" %sUninitialized value was created by a heap deallocation%s\n",
80 d
.Origin(), d
.Default());
82 case STACK_TRACE_TAG_POISON
:
83 Printf(" %sMemory was marked as uninitialized%s\n", d
.Origin(),
86 case STACK_TRACE_TAG_FIELDS
:
87 Printf(" %sMember fields were destroyed%s\n", d
.Origin(), d
.Default());
89 case STACK_TRACE_TAG_VPTR
:
90 Printf(" %sVirtual table ptr was destroyed%s\n", d
.Origin(),
94 Printf(" %sUninitialized value was created%s\n", d
.Origin(),
102 void ReportUMR(StackTrace
*stack
, u32 origin
) {
103 if (!__msan::flags()->report_umrs
) return;
105 ScopedErrorReportLock l
;
108 Printf("%s", d
.Warning());
109 Report("WARNING: MemorySanitizer: use-of-uninitialized-value\n");
110 Printf("%s", d
.Default());
113 DescribeOrigin(origin
);
115 ReportErrorSummary("use-of-uninitialized-value", stack
);
118 void ReportExpectedUMRNotFound(StackTrace
*stack
) {
119 ScopedErrorReportLock l
;
121 Printf("WARNING: Expected use of uninitialized value not found\n");
126 ScopedErrorReportLock l
;
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
);
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
);
143 void ReportAtExitStatistics() {
144 ScopedErrorReportLock l
;
146 if (msan_report_count
> 0) {
148 Printf("%s", d
.Warning());
149 Printf("MemorySanitizer: %d warnings reported.\n", msan_report_count
);
150 Printf("%s", d
.Default());
156 OriginSet() : next_id_(0) {}
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
;
166 int size() { return next_id_
; }
167 u32
get(int id
) { return origins_
[id
]; }
168 static char asChar(int id
) {
178 static const int OVERFLOW
= -1;
179 static const int MISSING
= -2;
182 static const int kMaxSize_
= 'Z' - 'A' + 1;
183 u32 origins_
[kMaxSize_
];
187 void DescribeMemoryRange(const void *x
, uptr size
) {
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;
194 size
= (size
+ 15) & ~15UL;
197 // Single letter names to origin id mapping.
198 OriginSet origin_set
;
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.
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());
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
));
224 last_quad_poisoned
= false;
226 // Print shadow byte.
227 if (s
< start
|| s
>= end
) {
230 unsigned char v
= *(unsigned char *)s
;
231 if (v
) last_quad_poisoned
= true;
232 Printf("%x%x", v
>> 4, v
& 0xf);
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
);
241 origin_ids
[(pos
% 16) / 4] = id
;
244 if (pos
% 16 == 15) {
247 for (int i
= 0; i
< 4; ++i
) {
248 char c
= OriginSet::asChar(origin_ids
[i
]);
250 if (i
!= 3) Printf(" ");
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
);
270 void ReportUMRInsideAddressRange(const char *function
, const void *start
,
271 uptr size
, uptr offset
) {
272 function
= StackTracePrinter::GetOrInit()->StripFunctionName(function
);
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
,
278 if (__sanitizer::Verbosity())
279 DescribeMemoryRange(start
, size
);
282 } // namespace __msan